Procházet zdrojové kódy

Merge pull request #1443 from aws-lumberyard-dev/nvsickle/MergeStabilizationJun18

Merge stabilization/2106 into development
Nicholas Van Sickle před 4 roky
rodič
revize
b032177418
100 změnil soubory, kde provedl 2561 přidání a 1021 odebrání
  1. 3 0
      AutomatedTesting/EngineFinder.cmake
  2. 1 2
      AutomatedTesting/Gem/PythonTests/NvCloth/TestSuite_Active.py
  3. 0 7
      AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt
  4. 0 96
      AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/auxiliary_content_tests.py
  5. 1 1
      AutomatedTesting/Gem/PythonTests/physics/C4044695_PhysXCollider_AddMultipleSurfaceFbx.py
  6. 7 0
      AutomatedTesting/Gem/PythonTests/physics/TestSuite_Periodic.py
  7. 2 2
      AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/C18977329_NvCloth_AddClothSimulationToMesh.ly
  8. 1 1
      AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/filelist.xml
  9. 2 2
      AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/level.pak
  10. 2 2
      AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/C18977330_NvCloth_AddClothSimulationToActor.ly
  11. 1 1
      AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/filelist.xml
  12. 2 2
      AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/level.pak
  13. 2 2
      AutomatedTesting/Levels/Physics/C5340400_RigidBody_ManualMomentOfInertia/C5340400_RigidBody_ManualMomentOfInertia.ly
  14. 115 0
      AutomatedTesting/Registry/C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override
  15. 115 0
      AutomatedTesting/Registry/C18977601_Material_FrictionCombinePriority.setreg_override
  16. 115 0
      AutomatedTesting/Registry/C18981526_Material_RestitutionCombinePriority.setreg_override
  17. 115 0
      AutomatedTesting/Registry/C4044456_Material_FrictionCombine.setreg_override
  18. 115 0
      AutomatedTesting/Registry/C4044457_Material_RestitutionCombine.setreg_override
  19. 115 0
      AutomatedTesting/Registry/C4044461_Material_Restitution.setreg_override
  20. 115 0
      AutomatedTesting/Registry/C4044697_Material_PerfaceMaterialValidation.setreg_override
  21. 408 397
      AutomatedTesting/ScriptCanvas/C12712455_ScriptCanvas_ShapeCastVerification.scriptcanvas
  22. 19 4
      Code/Framework/AzCore/AzCore/Math/ColorSerializer.cpp
  23. 2 0
      Code/Framework/AzCore/AzCore/Math/ColorSerializer.h
  24. 30 43
      Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.cpp
  25. 14 9
      Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.h
  26. 33 10
      Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp
  27. 16 12
      Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h
  28. 12 1
      Code/Framework/AzCore/AzCore/Math/TransformSerializer.cpp
  29. 2 0
      Code/Framework/AzCore/AzCore/Math/TransformSerializer.h
  30. 21 5
      Code/Framework/AzCore/AzCore/Math/UuidSerializer.cpp
  31. 2 0
      Code/Framework/AzCore/AzCore/Math/UuidSerializer.h
  32. 2 0
      Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl
  33. 46 19
      Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.cpp
  34. 7 1
      Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.h
  35. 2 1
      Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp
  36. 10 5
      Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h
  37. 20 5
      Code/Framework/AzCore/AzCore/Serialization/Json/BasicContainerSerializer.cpp
  38. 14 3
      Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.cpp
  39. 1 0
      Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.h
  40. 25 6
      Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.cpp
  41. 2 0
      Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.h
  42. 32 14
      Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.cpp
  43. 28 30
      Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.h
  44. 16 9
      Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp
  45. 3 2
      Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h
  46. 5 3
      Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.cpp
  47. 1 1
      Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerialization.cpp
  48. 10 4
      Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp
  49. 84 41
      Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.cpp
  50. 8 1
      Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.h
  51. 6 2
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
  52. 2 6
      Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h
  53. 4 0
      Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp
  54. 5 0
      Code/Framework/AzCore/Tests/Name/NameJsonSerializerTests.cpp
  55. 17 46
      Code/Framework/AzCore/Tests/Serialization/Json/ArraySerializerTests.cpp
  56. 21 3
      Code/Framework/AzCore/Tests/Serialization/Json/BasicContainerSerializerTests.cpp
  57. 18 0
      Code/Framework/AzCore/Tests/Serialization/Json/BoolSerializerTests.cpp
  58. 22 1
      Code/Framework/AzCore/Tests/Serialization/Json/DoubleSerializerTests.cpp
  59. 213 4
      Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h
  60. 115 13
      Code/Framework/AzCore/Tests/Serialization/Json/MapSerializerTests.cpp
  61. 44 0
      Code/Framework/AzCore/Tests/Serialization/Json/TestCases_Patching.cpp
  62. 7 6
      Code/Framework/AzCore/Tests/Serialization/Json/TupleSerializerTests.cpp
  63. 10 0
      Code/Framework/AzCore/Tests/Serialization/Json/UnorderedSetSerializerTests.cpp
  64. 2 1
      Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsEvents.h
  65. 1 1
      Code/Framework/AzFramework/AzFramework/Physics/Material.cpp
  66. 1 1
      Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp
  67. 22 33
      Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityTransformBus.h
  68. 23 9
      Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp
  69. 6 3
      Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h
  70. 3 1
      Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp
  71. 1 0
      Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h
  72. 31 12
      Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp
  73. 2 0
      Code/Framework/AzToolsFramework/CMakeLists.txt
  74. 37 0
      Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp
  75. 12 6
      Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
  76. 37 35
      Code/Framework/Tests/CMakeLists.txt
  77. 84 0
      Code/Framework/Tests/Mocks/MockSpawnableEntitiesInterface.h
  78. 1 0
      Code/Framework/Tests/framework_shared_tests_files.cmake
  79. 1 1
      Code/LauncherUnified/launcher_generator.cmake
  80. 0 1
      Code/Sandbox/Editor/CMakeLists.txt
  81. 1 8
      Code/Sandbox/Editor/CryEdit.cpp
  82. 0 2
      Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp
  83. 2 20
      Code/Sandbox/Editor/EditorPreferencesPageGeneral.cpp
  84. 0 4
      Code/Sandbox/Editor/EditorPreferencesPageGeneral.h
  85. 22 5
      Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
  86. 1 1
      Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
  87. 2 1
      Code/Tools/AssetBundler/tests/DummyProject/project.json
  88. 7 6
      Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp
  89. 9 9
      Code/Tools/AssetProcessor/native/utilities/BuilderManager.cpp
  90. 6 3
      Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
  91. 4 3
      Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp
  92. 1 0
      Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp
  93. 1 1
      Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp
  94. 21 9
      Code/Tools/SerializeContextTools/SliceConverter.cpp
  95. 3 1
      Gems/AWSCore/Code/CMakeLists.txt
  96. 1 1
      Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h
  97. 2 4
      Gems/AWSCore/Code/Source/Credential/AWSCVarCredentialHandler.cpp
  98. 19 12
      Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp
  99. 4 2
      Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp
  100. 3 0
      Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp

+ 3 - 0
AutomatedTesting/EngineFinder.cmake

@@ -15,6 +15,8 @@ include_guard()
 
 # Read the engine name from the project_json file
 file(READ ${CMAKE_CURRENT_LIST_DIR}/project.json project_json)
+set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/project.json)
+
 string(JSON LY_ENGINE_NAME_TO_USE ERROR_VARIABLE json_error GET ${project_json} engine)
 if(json_error)
     message(FATAL_ERROR "Unable to read key 'engine' from 'project.json', error: ${json_error}")
@@ -30,6 +32,7 @@ endif()
 # Find a key that matches LY_ENGINE_NAME_TO_USE and use that as the engine path.
 if(EXISTS ${manifest_path})
     file(READ ${manifest_path} manifest_json)
+    set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${manifest_path})
 
     string(JSON engines_path_count ERROR_VARIABLE json_error LENGTH ${manifest_json} engines_path)
     if(json_error)

+ 1 - 2
AutomatedTesting/Gem/PythonTests/NvCloth/TestSuite_Active.py

@@ -24,12 +24,11 @@ from base import TestAutomationBase
 @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
 @pytest.mark.parametrize("project", ["AutomatedTesting"])
 class TestAutomation(TestAutomationBase):
-    @pytest.mark.xfail(reason="Running with atom null renderer is causing this test to fail")
+
     def test_C18977329_NvCloth_AddClothSimulationToMesh(self, request, workspace, editor, launcher_platform):
         from . import C18977329_NvCloth_AddClothSimulationToMesh as test_module
         self._run_test(request, workspace, editor, test_module)
 
-    @pytest.mark.xfail(reason="Running with atom null renderer is causing this test to fail")
     def test_C18977330_NvCloth_AddClothSimulationToActor(self, request, workspace, editor, launcher_platform):
         from . import C18977330_NvCloth_AddClothSimulationToActor as test_module
         self._run_test(request, workspace, editor, test_module)

+ 0 - 7
AutomatedTesting/Gem/PythonTests/assetpipeline/CMakeLists.txt

@@ -13,13 +13,6 @@ add_subdirectory(asset_processor_tests)
 
 if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
 ## AP Python Tests ##
-    ly_add_pytest(
-        NAME AssetPipelineTests.AuxiliaryContent
-        PATH ${CMAKE_CURRENT_LIST_DIR}/auxiliary_content_tests/auxiliary_content_tests.py
-        EXCLUDE_TEST_RUN_TARGET_FROM_IDE
-        TEST_SUITE periodic
-    )
-
     ly_add_pytest(
         NAME AssetPipelineTests.BankInfoParser
         PATH ${CMAKE_CURRENT_LIST_DIR}/wwise_bank_dependency_tests/bank_info_parser_tests.py

+ 0 - 96
AutomatedTesting/Gem/PythonTests/assetpipeline/auxiliary_content_tests/auxiliary_content_tests.py

@@ -1,96 +0,0 @@
-"""
-All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-its licensors.
-
-For complete copyright and license terms please see the LICENSE at the root of this
-distribution (the "License"). All use of this software is governed by the License,
-or, if provided, by the license below or the license accompanying this file. Do not
-remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-
-"""
-import pytest
-import ly_test_tools
-
-import os
-import sys
-import shutil
-import subprocess
-import glob
-from ly_test_tools.builtin.helpers import *
-from ly_test_tools.environment.process_utils import *
-from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
-
-logger = logging.getLogger(__name__)
-
-project_list = ['AutomatedTesting']
-
[email protected]
[email protected]_periodic
-class TestAuxiliaryContent:
-    @pytest.fixture(autouse=True)
-    def setup_teardown(self, request, workspace, project):
-        path_to_dev = workspace.paths.engine_root()
-        os.chdir(path_to_dev)
-        auxiliaryContentDirName = str.lower(project) + f"_{ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]}_paks"
-        self.auxiliaryContentPath = os.path.join(path_to_dev, auxiliaryContentDirName)
-
-        def teardown():
-            if (os.path.exists(self.auxiliaryContentPath)):
-                shutil.rmtree(self.auxiliaryContentPath)
-
-        request.addfinalizer(teardown)
-
-    @staticmethod
-    def scanForLevelPak(path_toscan):
-        files = glob.glob('{0}/**/level.pak'.format(path_toscan), recursive=True)
-        return len(files)
-
-    @pytest.mark.parametrize('level', ['alldependencies'])
-    @pytest.mark.parametrize('project', project_list)
-    def test_CreateAuxiliaryContent_DontSkipLevelPaks(self, workspace, level):
-        """
-        This test ensure that Auxiliary Content contain level.pak files
-
-        Test Steps:
-        1. Run auxiliary content against project under test
-        2. Validate auxiliary content exists
-        3. Verifies that level.pak exists
-        """
-
-        path_to_dev = workspace.paths.engine_root()
-        bin_path = workspace.paths.build_directory()
-
-        auxiliaryContentScriptPath = os.path.join(path_to_dev, 'BuildReleaseAuxiliaryContent.py')
-        subprocess.check_call(['python', auxiliaryContentScriptPath,
-                               "--buildFolder={0}".format(bin_path),
-                               "--platforms=pc",
-                               f"--project-path={workspace.project}"])
-
-        assert os.path.exists(self.auxiliaryContentPath)
-        assert not self.scanForLevelPak(self.auxiliaryContentPath) == 0
-
-    @pytest.mark.parametrize('level', ['alldependencies'])
-    @pytest.mark.parametrize('project', project_list)
-    def test_CreateAuxiliaryContent_SkipLevelPaks(self, workspace, level):
-        """
-        This test ensure that Auxiliary Content contain no level.pak file
-
-        Test Steps:
-        1. Run auxiliary content against project under test with skiplevelPaks flag
-        2. Validate auxiliary content exists
-        3. Validate level.pak was added to auxiliary content
-        """
-
-        path_to_dev = workspace.paths.engine_root()
-        bin_path = workspace.paths.build_directory()
-
-        auxiliaryContentScriptPath = os.path.join(path_to_dev, 'BuildReleaseAuxiliaryContent.py')
-        subprocess.check_call(['python', auxiliaryContentScriptPath,
-                               "--buildFolder={0}".format(bin_path),
-                               "--platforms=pc",
-                               "--skiplevelPaks",
-                               f"--project-path={workspace.project}"])
-        assert os.path.exists(self.auxiliaryContentPath)
-
-        assert self.scanForLevelPak(self.auxiliaryContentPath) == 0

+ 1 - 1
AutomatedTesting/Gem/PythonTests/physics/C4044695_PhysXCollider_AddMultipleSurfaceFbx.py

@@ -102,7 +102,7 @@ def C4044695_PhysXCollider_AddMultipleSurfaceFbx():
     # 6) Check if multiple material slots show up under Materials section in the PhysX Collider component
     pte = collider_component.get_property_tree()
     def get_surface_count():
-        count = pte.get_container_count("Collider Configuration|Physics Material|Mesh Surfaces")
+        count = pte.get_container_count("Collider Configuration|Physics Materials|Slots")
         return count.GetValue()
 
     Report.result(

+ 7 - 0
AutomatedTesting/Gem/PythonTests/physics/TestSuite_Periodic.py

@@ -93,11 +93,13 @@ class TestAutomation(TestAutomationBase):
         self._run_test(request, workspace, editor, test_module)
 
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C4044457_Material_RestitutionCombine.setreg_override', 'AutomatedTesting/Registry')
     def test_C4044457_Material_RestitutionCombine(self, request, workspace, editor, launcher_platform):
         from . import C4044457_Material_RestitutionCombine as test_module
         self._run_test(request, workspace, editor, test_module)
 
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C4044456_Material_FrictionCombine.setreg_override', 'AutomatedTesting/Registry')
     def test_C4044456_Material_FrictionCombine(self, request, workspace, editor, launcher_platform):
         from . import C4044456_Material_FrictionCombine as test_module
         self._run_test(request, workspace, editor, test_module)
@@ -194,6 +196,7 @@ class TestAutomation(TestAutomationBase):
         self._run_test(request, workspace, editor, test_module)
 
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C18981526_Material_RestitutionCombinePriority.setreg_override', 'AutomatedTesting/Registry')
     def test_C18981526_Material_RestitutionCombinePriority(self, request, workspace, editor, launcher_platform):
         from . import C18981526_Material_RestitutionCombinePriority as test_module
         self._run_test(request, workspace, editor, test_module)
@@ -229,6 +232,7 @@ class TestAutomation(TestAutomationBase):
         self._run_test(request, workspace, editor, test_module)
 
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C18977601_Material_FrictionCombinePriority.setreg_override', 'AutomatedTesting/Registry')
     def test_C18977601_Material_FrictionCombinePriority(self, request, workspace, editor, launcher_platform):
         from . import C18977601_Material_FrictionCombinePriority as test_module
         self._run_test(request, workspace, editor, test_module)
@@ -250,6 +254,7 @@ class TestAutomation(TestAutomationBase):
     @pytest.mark.xfail(
         reason="This test needs new physics asset with multiple materials to be more stable.")
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C4044697_Material_PerfaceMaterialValidation.setreg_override', 'AutomatedTesting/Registry')
     def test_C4044697_Material_PerfaceMaterialValidation(self, request, workspace, editor, launcher_platform):
         from . import C4044697_Material_PerfaceMaterialValidation as test_module
         self._run_test(request, workspace, editor, test_module)
@@ -282,6 +287,7 @@ class TestAutomation(TestAutomationBase):
         self._run_test(request, workspace, editor, test_module)
 
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override', 'AutomatedTesting/Registry')
     def test_C15556261_PhysXMaterials_CharacterControllerMaterialAssignment(self, request, workspace, editor, launcher_platform):
         from . import C15556261_PhysXMaterials_CharacterControllerMaterialAssignment as test_module
         self._run_test(request, workspace, editor, test_module)
@@ -326,6 +332,7 @@ class TestAutomation(TestAutomationBase):
         self._run_test(request, workspace, editor, test_module)
 
     @revert_physics_config
+    @fm.file_override('physxsystemconfiguration.setreg','C4044461_Material_Restitution.setreg_override', 'AutomatedTesting/Registry')
     def test_C4044461_Material_Restitution(self, request, workspace, editor, launcher_platform):
         from . import C4044461_Material_Restitution as test_module
         self._run_test(request, workspace, editor, test_module)

+ 2 - 2
AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/C18977329_NvCloth_AddClothSimulationToMesh.ly

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:e15d484113e8151072b410924747a8ad304f6f12457fad577308c0491693ab34
-size 5472
+oid sha256:6517300fb1ce70c4696286e14715c547cfd175eabbb2042f7f2a456b15054224
+size 5253

+ 1 - 1
AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/filelist.xml

@@ -1,6 +1,6 @@
 <download name="C18977329_NvCloth_AddClothSimulationToMesh" type="Map">
  <index src="filelist.xml" dest="filelist.xml"/>
  <files>
-  <file src="level.pak" dest="level.pak" size="97C8" md5="64e64e1e3345dacace01dde152c72250"/>
+  <file src="level.pak" dest="level.pak" size="96A3" md5="db8a235878128076005ade018587f536"/>
  </files>
 </download>

+ 2 - 2
AutomatedTesting/Levels/NvCloth/C18977329_NvCloth_AddClothSimulationToMesh/level.pak

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:64de37c805b0be77cdb7a85b5406af58b7f845e7d97fec1721ac5d789bb641db
-size 38856
+oid sha256:ce32a7cdf3ed37751385b3bb18f05206702978363f325d06727b5eb20d40b7eb
+size 38563

+ 2 - 2
AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/C18977330_NvCloth_AddClothSimulationToActor.ly

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:7b595323d4d51211463dea0338abb6ce2a4a0a8d41efb12ac3c9dccd1f972171
-size 5504
+oid sha256:89dbcec013cb819e52ec0f8fed0a9e417fd32eac8aeb67d3958266bb6089ec21
+size 5505

+ 1 - 1
AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/filelist.xml

@@ -1,6 +1,6 @@
 <download name="C18977330_NvCloth_AddClothSimulationToActor" type="Map">
  <index src="filelist.xml" dest="filelist.xml"/>
  <files>
-  <file src="level.pak" dest="level.pak" size="9941" md5="297730934d657d7ca57a7357ee9cd566"/>
+  <file src="level.pak" dest="level.pak" size="E16" md5="036b4a87cbb256f76823549ab4b18c05"/>
  </files>
 </download>

+ 2 - 2
AutomatedTesting/Levels/NvCloth/C18977330_NvCloth_AddClothSimulationToActor/level.pak

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:617c455668fc41cb7fd69de690e4aa3c80f2cb36deaa371902b79de18fcd1cb2
-size 39233
+oid sha256:622c2624b04e07b704520f32c458b50d5a50de1ef116b7bc9c3c0ccb6f4a4ecc
+size 3606

+ 2 - 2
AutomatedTesting/Levels/Physics/C5340400_RigidBody_ManualMomentOfInertia/C5340400_RigidBody_ManualMomentOfInertia.ly

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b6e408095c15a388768b7f70b6049f33c894aab3e51f2d744bc1ae1d18668ee4
-size 9694
+oid sha256:824a51a375f19274d5698ff08af0fdc3dc18204505c73a943de748455d108b01
+size 6181

+ 115 - 0
AutomatedTesting/Registry/C15556261_PhysXMaterials_CharacterControllerMaterialAssignment.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{70D4A444-AFD4-57C4-9885-63F25AC3C281}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c15556261_physxmaterials_charactercontrollermaterialassignment/library.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

+ 115 - 0
AutomatedTesting/Registry/C18977601_Material_FrictionCombinePriority.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{B8749DAB-15DA-5A61-B565-C853673604CD}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c18977601_material_frictioncombinepriority/friction_combine.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

+ 115 - 0
AutomatedTesting/Registry/C18981526_Material_RestitutionCombinePriority.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{AED48B18-0F3F-5E59-A8FF-30DB134B307B}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c18981526_material_restitutioncombinepriority/restitution_combine.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

+ 115 - 0
AutomatedTesting/Registry/C4044456_Material_FrictionCombine.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{8D2C4A29-E0FC-564F-82C9-24BBA30C5A90}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c4044456_material_frictioncombine/friction_combine.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

+ 115 - 0
AutomatedTesting/Registry/C4044457_Material_RestitutionCombine.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{D5D6A6DE-E636-5638-B30D-6CE2FDC321F8}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c4044457_material_restitutioncombine/restitution_combine.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

+ 115 - 0
AutomatedTesting/Registry/C4044461_Material_Restitution.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{E4117B5B-8D9A-5C1D-BA1E-C36542A6588D}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c4044461_material_restitution/restitution.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

+ 115 - 0
AutomatedTesting/Registry/C4044697_Material_PerfaceMaterialValidation.setreg_override

@@ -0,0 +1,115 @@
+{
+    "Amazon": {
+        "Gems": {
+            "PhysX": {
+                "PhysXSystemConfiguration": {
+                    "CollisionConfig": {
+                        "Layers": {
+                            "LayerNames": [
+                                "Default",
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                {},
+                                "TouchBend"
+                            ]
+                        },
+                        "Groups": {
+                            "GroupPresets": [
+                                {
+                                    "Name": "All",
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{CDB6B8D8-5CD0-40A8-874D-839B00A92EBB}"
+                                    },
+                                    "Name": "None",
+                                    "Group": {
+                                        "Mask": 0
+                                    },
+                                    "ReadOnly": true
+                                },
+                                {
+                                    "Id": {
+                                        "GroupId": "{22769429-5D46-429B-829A-0115239D9AAA}"
+                                    },
+                                    "Name": "All_NoTouchBend",
+                                    "Group": {
+                                        "Mask": 9223372036854775807
+                                    },
+                                    "ReadOnly": true
+                                }
+                            ]
+                        }
+                    },
+                    "MaterialLibrary": {
+                        "assetId": {
+                            "guid": "{2E85B457-ED19-5FE3-90B4-6EFFB4D0E682}"
+                        },
+                        "loadBehavior": "QueueLoad",
+                        "assetHint": "levels/physics/c4044697_material_perfacematerialvalidation/test_library.physmaterial"
+                    }
+                }
+            }
+        }
+    }
+}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 408 - 397
AutomatedTesting/ScriptCanvas/C12712455_ScriptCanvas_ShapeCastVerification.scriptcanvas


+ 19 - 4
Code/Framework/AzCore/AzCore/Math/ColorSerializer.cpp

@@ -36,6 +36,12 @@ namespace AZ
         Color* color = reinterpret_cast<Color*>(outputValue);
         AZ_Assert(color, "Output value for JsonColorSerializer can't be null.");
 
+        if (IsExplicitDefault(inputValue))
+        {
+            *color = Color::CreateZero();
+            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Color value set to default of zero.");
+        }
+
         switch (inputValue.GetType())
         {
         case rapidjson::kArrayType:
@@ -43,10 +49,14 @@ namespace AZ
         case rapidjson::kObjectType:
             return LoadObject(*color, inputValue, context);
         
-        case rapidjson::kStringType: // fall through
-        case rapidjson::kNumberType: // fall through
-        case rapidjson::kNullType:   // fall through
-        case rapidjson::kFalseType:  // fall through
+        case rapidjson::kStringType:
+            [[fallthrough]];
+        case rapidjson::kNumberType:
+            [[fallthrough]];
+        case rapidjson::kNullType:
+            [[fallthrough]];
+        case rapidjson::kFalseType:
+            [[fallthrough]];
         case rapidjson::kTrueType:
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                 "Unsupported type. Colors can only be read from arrays or objects.");
@@ -91,6 +101,11 @@ namespace AZ
         }
     }
 
+    auto JsonColorSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
     JsonSerializationResult::Result JsonColorSerializer::LoadObject(Color& output, const rapidjson::Value& inputValue, 
         JsonDeserializerContext& context)
     {

+ 2 - 0
Code/Framework/AzCore/AzCore/Math/ColorSerializer.h

@@ -28,6 +28,8 @@ namespace AZ
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
 
+        OperationFlags GetOperationsFlags() const override;
+
     private:
         enum class LoadAlpha
         {

+ 30 - 43
Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.cpp

@@ -263,7 +263,7 @@ namespace AZ::JsonMathMatrixSerializerInternal
 
     template<typename MatrixType, size_t RowCount, size_t ColumnCount>
     JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId,
-        const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+        const rapidjson::Value& inputValue, JsonDeserializerContext& context, bool isExplicitDefault)
     {
         namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
 
@@ -279,6 +279,12 @@ namespace AZ::JsonMathMatrixSerializerInternal
         MatrixType* matrix = reinterpret_cast<MatrixType*>(outputValue);
         AZ_Assert(matrix, "Output value for JsonMatrix%zux%zuSerializer can't be null.", RowCount, ColumnCount);
 
+        if (isExplicitDefault)
+        {
+            *matrix = MatrixType::CreateIdentity();
+            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Matrix value set to identity matrix.");
+        }
+
         switch (inputValue.GetType())
         {
         case rapidjson::kArrayType:
@@ -381,6 +387,16 @@ namespace AZ::JsonMathMatrixSerializerInternal
 
 namespace AZ
 {
+    // BaseJsonMatrixSerializer
+
+    AZ_CLASS_ALLOCATOR_IMPL(BaseJsonMatrixSerializer, SystemAllocator, 0);
+
+    auto BaseJsonMatrixSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
+
     // Matrix3x3
 
     AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix3x3Serializer, SystemAllocator, 0);
@@ -389,10 +405,7 @@ namespace AZ
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
         return JsonMathMatrixSerializerInternal::Load<Matrix3x3, 3, 3>(
-            outputValue,
-            outputValueTypeId,
-            inputValue,
-            context);
+            outputValue, outputValueTypeId, inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonMatrix3x3Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -401,11 +414,7 @@ namespace AZ
         outputValue.SetObject();
 
         return JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix3x3>(
-            outputValue,
-            inputValue,
-            defaultValue,
-            valueTypeId,
-            context);
+            outputValue, inputValue, defaultValue, valueTypeId, context);
     }
 
 
@@ -417,10 +426,7 @@ namespace AZ
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
         return JsonMathMatrixSerializerInternal::Load<Matrix3x4, 3, 4>(
-            outputValue,
-            outputValueTypeId,
-            inputValue,
-            context);
+            outputValue, outputValueTypeId, inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonMatrix3x4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -428,19 +434,11 @@ namespace AZ
     {
         outputValue.SetObject();
 
-        auto result = JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix3x4>(
-            outputValue,
-            inputValue,
-            defaultValue,
-            valueTypeId,
-            context);
+        auto result =
+            JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix3x4>(outputValue, inputValue, defaultValue, valueTypeId, context);
 
-        auto resultTranslation = JsonMathMatrixSerializerInternal::StoreTranslation<Matrix3x4>(
-            outputValue,
-            inputValue,
-            defaultValue,
-            valueTypeId,
-            context);
+        auto resultTranslation =
+            JsonMathMatrixSerializerInternal::StoreTranslation<Matrix3x4>(outputValue, inputValue, defaultValue, valueTypeId, context);
 
         result.GetResultCode().Combine(resultTranslation);
         return result;
@@ -454,10 +452,7 @@ namespace AZ
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
         return JsonMathMatrixSerializerInternal::Load<Matrix4x4, 4, 4>(
-            outputValue,
-            outputValueTypeId,
-            inputValue,
-            context);
+            outputValue, outputValueTypeId, inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonMatrix4x4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -465,19 +460,11 @@ namespace AZ
     {
         outputValue.SetObject();
 
-        auto result = JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix4x4>(
-            outputValue,
-            inputValue,
-            defaultValue,
-            valueTypeId,
-            context);
-
-        auto resultTranslation = JsonMathMatrixSerializerInternal::StoreTranslation<Matrix4x4>(
-            outputValue,
-            inputValue,
-            defaultValue,
-            valueTypeId,
-            context);
+        auto result =
+            JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix4x4>(outputValue, inputValue, defaultValue, valueTypeId, context);
+
+        auto resultTranslation =
+            JsonMathMatrixSerializerInternal::StoreTranslation<Matrix4x4>(outputValue, inputValue, defaultValue, valueTypeId, context);
 
         result.GetResultCode().Combine(resultTranslation);
         return result;

+ 14 - 9
Code/Framework/AzCore/AzCore/Math/MathMatrixSerializer.h

@@ -16,11 +16,18 @@
 
 namespace AZ
 {
-    class JsonMatrix3x3Serializer
-        : public BaseJsonSerializer
+    class BaseJsonMatrixSerializer : public BaseJsonSerializer
     {
     public:
-        AZ_RTTI(JsonMatrix3x3Serializer, "{8C76CD6A-8576-4604-A746-CF7A7F20F366}", BaseJsonSerializer);
+        AZ_RTTI(BaseJsonMatrixSerializer, "{18CA4637-C9B7-454B-9126-107E18A8C096}", BaseJsonSerializer);
+        AZ_CLASS_ALLOCATOR_DECL;
+        OperationFlags GetOperationsFlags() const override;
+    };
+
+    class JsonMatrix3x3Serializer : public BaseJsonMatrixSerializer
+    {
+    public:
+        AZ_RTTI(JsonMatrix3x3Serializer, "{8C76CD6A-8576-4604-A746-CF7A7F20F366}", BaseJsonMatrixSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -28,11 +35,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonMatrix3x4Serializer
-        : public BaseJsonSerializer
+    class JsonMatrix3x4Serializer : public BaseJsonMatrixSerializer
     {
     public:
-        AZ_RTTI(JsonMatrix3x4Serializer, "{E801333B-4AF1-4F43-976C-579670B02DC5}", BaseJsonSerializer);
+        AZ_RTTI(JsonMatrix3x4Serializer, "{E801333B-4AF1-4F43-976C-579670B02DC5}", BaseJsonMatrixSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -40,11 +46,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonMatrix4x4Serializer
-        : public BaseJsonSerializer
+    class JsonMatrix4x4Serializer : public BaseJsonMatrixSerializer
     {
     public:
-        AZ_RTTI(JsonMatrix4x4Serializer, "{46E888FC-248A-4910-9221-4E101A10AEA1}", BaseJsonSerializer);
+        AZ_RTTI(JsonMatrix4x4Serializer, "{46E888FC-248A-4910-9221-4E101A10AEA1}", BaseJsonMatrixSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;

+ 33 - 10
Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.cpp

@@ -124,7 +124,7 @@ namespace AZ
 
         template<typename VectorType, size_t ElementCount>
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
-            JsonDeserializerContext& context)
+            JsonDeserializerContext& context, bool isExplicitDefault)
         {
             namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
 
@@ -138,6 +138,12 @@ namespace AZ
             VectorType* vector = reinterpret_cast<VectorType*>(outputValue);
             AZ_Assert(vector, "Output value for JsonVector%iSerializer can't be null.", ElementCount);
 
+            if (isExplicitDefault)
+            {
+                *vector = VectorType::CreateZero();
+                return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Math vector value set to default of zero.");
+            }
+
             switch (inputValue.GetType())
             {
             case rapidjson::kArrayType:
@@ -145,10 +151,14 @@ namespace AZ
             case rapidjson::kObjectType:
                 return LoadObject<VectorType, ElementCount>(*vector, inputValue, context);
 
-            case rapidjson::kStringType: // fall through
-            case rapidjson::kNumberType: // fall through
-            case rapidjson::kNullType:   // fall through
-            case rapidjson::kFalseType:  // fall through
+            case rapidjson::kStringType:
+                [[fallthrough]];
+            case rapidjson::kNumberType:
+                [[fallthrough]];
+            case rapidjson::kNullType:
+                [[fallthrough]];
+            case rapidjson::kFalseType:
+                [[fallthrough]];
             case rapidjson::kTrueType:
                 return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                     "Unsupported type. Math vectors can only be read from arrays or objects.");
@@ -189,6 +199,16 @@ namespace AZ
         }
     }
 
+
+    // BaseJsonVectorSerializer
+
+    AZ_CLASS_ALLOCATOR_IMPL(BaseJsonVectorSerializer, SystemAllocator, 0);
+
+    auto BaseJsonVectorSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
     
     // Vector2
 
@@ -197,7 +217,8 @@ namespace AZ
     JsonSerializationResult::Result JsonVector2Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
-        return JsonMathVectorSerializerInternal::Load<Vector2, 2>(outputValue, outputValueTypeId, inputValue, context);
+        return JsonMathVectorSerializerInternal::Load<Vector2, 2>(
+            outputValue, outputValueTypeId, inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonVector2Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -214,7 +235,8 @@ namespace AZ
     JsonSerializationResult::Result JsonVector3Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
-        return JsonMathVectorSerializerInternal::Load<Vector3, 3>(outputValue, outputValueTypeId, inputValue, context);
+        return JsonMathVectorSerializerInternal::Load<Vector3, 3>(
+            outputValue, outputValueTypeId, inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonVector3Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -231,7 +253,8 @@ namespace AZ
     JsonSerializationResult::Result JsonVector4Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
-        return JsonMathVectorSerializerInternal::Load<Vector4, 4>(outputValue, outputValueTypeId, inputValue, context);
+        return JsonMathVectorSerializerInternal::Load<Vector4, 4>(
+            outputValue, outputValueTypeId, inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonVector4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -252,7 +275,7 @@ namespace AZ
         // check for "yaw, pitch, roll" object
         if (inputValue.IsObject())
         {
-            if (inputValue.GetObject().ObjectEmpty())
+            if (IsExplicitDefault(inputValue))
             {
                 Quaternion* outQuaternion = reinterpret_cast<Quaternion*>(outputValue);
                 *outQuaternion = Quaternion::CreateIdentity();
@@ -283,7 +306,7 @@ namespace AZ
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read quaternion.");
         }
 
-        return JsonMathVectorSerializerInternal::Load<Quaternion, 4>(outputValue, outputValueTypeId, inputValue, context);
+        return JsonMathVectorSerializerInternal::Load<Quaternion, 4>(outputValue, outputValueTypeId, inputValue, context, false);
     }
 
     JsonSerializationResult::Result JsonQuaternionSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,

+ 16 - 12
Code/Framework/AzCore/AzCore/Math/MathVectorSerializer.h

@@ -16,11 +16,18 @@
 
 namespace AZ
 {
-    class JsonVector2Serializer
-        : public BaseJsonSerializer
+    class BaseJsonVectorSerializer : public BaseJsonSerializer
     {
     public:
-        AZ_RTTI(JsonVector2Serializer, "{E1EAA209-9682-4120-B26B-3EDD9AD56D6F}", BaseJsonSerializer);
+        AZ_RTTI(BaseJsonVectorSerializer, "{C188D355-E6DF-4590-8B31-F40591F48A8E}", BaseJsonSerializer);
+        AZ_CLASS_ALLOCATOR_DECL;
+        OperationFlags GetOperationsFlags() const override;
+    };
+
+    class JsonVector2Serializer : public BaseJsonVectorSerializer
+    {
+    public:
+        AZ_RTTI(JsonVector2Serializer, "{E1EAA209-9682-4120-B26B-3EDD9AD56D6F}", BaseJsonVectorSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -28,11 +35,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonVector3Serializer
-        : public BaseJsonSerializer
+    class JsonVector3Serializer : public BaseJsonVectorSerializer
     {
     public:
-        AZ_RTTI(JsonVector3Serializer, "{BF82BBF3-3CD9-48DA-97CC-E4DF2EF01552}", BaseJsonSerializer);
+        AZ_RTTI(JsonVector3Serializer, "{BF82BBF3-3CD9-48DA-97CC-E4DF2EF01552}", BaseJsonVectorSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -40,11 +46,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonVector4Serializer
-        : public BaseJsonSerializer
+    class JsonVector4Serializer : public BaseJsonVectorSerializer
     {
     public:
-        AZ_RTTI(JsonVector4Serializer, "{05B45EA7-7102-4281-8AA0-2AC72D74AAFD}", BaseJsonSerializer);
+        AZ_RTTI(JsonVector4Serializer, "{05B45EA7-7102-4281-8AA0-2AC72D74AAFD}", BaseJsonVectorSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -52,11 +57,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonQuaternionSerializer
-        : public BaseJsonSerializer
+    class JsonQuaternionSerializer : public BaseJsonVectorSerializer
     {
     public:
-        AZ_RTTI(JsonQuaternionSerializer, "{18604375-3606-49AC-B366-0F6DF9149FF3}", BaseJsonSerializer);
+        AZ_RTTI(JsonQuaternionSerializer, "{18604375-3606-49AC-B366-0F6DF9149FF3}", BaseJsonVectorSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;

+ 12 - 1
Code/Framework/AzCore/AzCore/Math/TransformSerializer.cpp

@@ -33,6 +33,12 @@ namespace AZ
         AZ::Transform* transformInstance = reinterpret_cast<AZ::Transform*>(outputValue);
         AZ_Assert(transformInstance, "Output value for JsonTransformSerializer can't be null.");
 
+        if (IsExplicitDefault(inputValue))
+        {
+            *transformInstance = AZ::Transform::CreateIdentity();
+            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Transform value set to identity.");
+        }
+
         JSR::ResultCode result(JSR::Tasks::ReadField);
 
         {
@@ -72,7 +78,7 @@ namespace AZ
 
         return context.Report(
             result,
-            result.GetProcessing() != JSR::Processing::Halted ? "Succesfully loaded Transform information."
+            result.GetProcessing() != JSR::Processing::Halted ? "Successfully loaded Transform information."
                                                               : "Failed to load Transform information.");
     }
 
@@ -140,4 +146,9 @@ namespace AZ
                                                               : "Failed to store Transform information.");
     }
 
+    auto JsonTransformSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
 } // namespace AZ

+ 2 - 0
Code/Framework/AzCore/AzCore/Math/TransformSerializer.h

@@ -30,6 +30,8 @@ namespace AZ
             rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId,
             JsonSerializerContext& context) override;
 
+        OperationFlags GetOperationsFlags() const override;
+        
     private:
         // Note: These need to be defined as "const char[]" instead of "const char*" so that they can be implicitly converted
         // to a rapidjson::GenericStringRef<>.  (This also lets rapidjson get the string length at compile time)

+ 21 - 5
Code/Framework/AzCore/AzCore/Math/UuidSerializer.cpp

@@ -33,6 +33,11 @@ namespace AZ
             AZStd::regex_constants::icase | AZStd::regex_constants::optimize);
     }
 
+    auto JsonUuidSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
     JsonSerializationResult::Result JsonUuidSerializer::Load(void* outputValue, const Uuid& outputValueTypeId,
         const rapidjson::Value& inputValue, JsonDeserializerContext& context)
     {
@@ -53,13 +58,24 @@ namespace AZ
 
         Uuid* valAsUuid = reinterpret_cast<Uuid*>(outputValue);
 
+        if (IsExplicitDefault(inputValue))
+        {
+            *valAsUuid = AZ::Uuid::CreateNull();
+            return MessageResult("Uuid value set to default of null.", JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed));
+        }
+
         switch (inputValue.GetType())
         {
-        case rapidjson::kArrayType: // fallthrough
-        case rapidjson::kObjectType:// fallthrough
-        case rapidjson::kFalseType: // fallthrough
-        case rapidjson::kTrueType:  // fallthrough
-        case rapidjson::kNumberType:// fallthrough
+        case rapidjson::kArrayType:
+            [[fallthrough]];
+        case rapidjson::kObjectType:
+            [[fallthrough]];
+        case rapidjson::kFalseType:
+            [[fallthrough]];
+        case rapidjson::kTrueType:
+            [[fallthrough]];
+        case rapidjson::kNumberType:
+            [[fallthrough]];
         case rapidjson::kNullType:
             return MessageResult("Unsupported type. Uuids can only be read from strings.",
                 JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported));

+ 2 - 0
Code/Framework/AzCore/AzCore/Math/UuidSerializer.h

@@ -41,6 +41,8 @@ namespace AZ
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
 
+        OperationFlags GetOperationsFlags() const override;
+
         //! Does the same as load, but doesn't report through the provided callback in the settings. Instead the final
         //! ResultCode and message are returned and it's up to the caller to report if need needed.
         MessageResult UnreportedLoad(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue);

+ 2 - 0
Code/Framework/AzCore/AzCore/RTTI/AzStdOnDemandReflection.inl

@@ -406,6 +406,7 @@ namespace AZ
                 AZStd::vector<AZ::BehaviorParameter> eventParamsTypes{ AZStd::initializer_list<AZ::BehaviorParameter>{
                     CreateBehaviorEventParameter<decay_array<T>>()... } };
                 behaviorContext->Class<AZ::Event<T...>>()
+                    ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly)
                     ->Attribute(AZ::Script::Attributes::EventHandlerCreationFunction, createHandlerHolder)
                     ->Attribute(AZ::Script::Attributes::EventParameterTypes, eventParamsTypes)
                     ->Method("HasHandlerConnected", &AZ::Event<T...>::HasHandlerConnected)
@@ -413,6 +414,7 @@ namespace AZ
 
                 behaviorContext->Class<AZ::EventHandler<T...>>()
                     ->Method("Disconnect", &AZ::EventHandler<T...>::Disconnect)
+                        ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::ListOnly)
                     ;
             }
         }

+ 46 - 19
Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.cpp

@@ -32,13 +32,24 @@ namespace AZ
         switch (inputValue.GetType())
         {
         case rapidjson::kArrayType:
-            return LoadContainer(outputValue, outputValueTypeId, inputValue, context);
+            return LoadContainer(outputValue, outputValueTypeId, inputValue, false, context);
 
-        case rapidjson::kObjectType: // fall through
-        case rapidjson::kNullType: // fall through
-        case rapidjson::kStringType: // fall through
-        case rapidjson::kFalseType: // fall through
-        case rapidjson::kTrueType: // fall through
+        case rapidjson::kObjectType:
+            if (IsExplicitDefault(inputValue))
+            {
+                // Because this serializer has only the operation flag "InitializeNewInstance" set, the only time this will be called with
+                // an explicit default is when a new instance has been created.
+                return LoadContainer(outputValue, outputValueTypeId, inputValue, true, context);
+            }
+            [[fallthrough]];
+        case rapidjson::kNullType:
+            [[fallthrough]];
+        case rapidjson::kStringType:
+            [[fallthrough]];
+        case rapidjson::kFalseType:
+            [[fallthrough]];
+        case rapidjson::kTrueType:
+            [[fallthrough]];
         case rapidjson::kNumberType:
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                 "Unsupported type. AZStd::array entries can only be read from an array.");
@@ -129,7 +140,16 @@ namespace AZ
         }
     }
 
-    JsonSerializationResult::Result JsonArraySerializer::LoadContainer(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+    auto JsonArraySerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
+    JsonSerializationResult::Result JsonArraySerializer::LoadContainer(
+        void* outputValue,
+        const Uuid& outputValueTypeId,
+        const rapidjson::Value& inputValue,
+        bool isNewInstance,
         JsonDeserializerContext& context)
     {
         namespace JSR = JsonSerializationResult; // Used to remove name conflicts in AzCore in uber builds.
@@ -154,14 +174,7 @@ namespace AZ
                 "Unable to retrieve the correct container information for AZStd::array instance.");
         }
 
-        const size_t size = container->Size(outputValue);
-        if (inputValue.Size() < size)
-        {
-            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
-                "Not enough entries in JSON array to load an AZStd::array from.");
-        }
-
-        ContinuationFlags flags = ContinuationFlags::None;
+        ContinuationFlags flags = isNewInstance ? ContinuationFlags::LoadAsNewInstance : ContinuationFlags::None;
         Uuid elementTypeId = Uuid::CreateNull();
         auto typeEnumCallback = [&elementTypeId, &flags](const Uuid&, const SerializeContext::ClassElement* genericClassElement)
         {
@@ -175,13 +188,23 @@ namespace AZ
         };
         container->EnumTypes(typeEnumCallback);
 
+        const size_t size = container->Size(outputValue);
+        if (!isNewInstance && inputValue.Size() < size)
+        {
+            return context.Report(
+                JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Not enough entries in JSON array to load an AZStd::array from.");
+        }
+
+        rapidjson::Value explicitDefaultValue = GetExplicitDefault();
+        
         JSR::ResultCode retVal(JSR::Tasks::ReadField);
         for (size_t i = 0; i < size; ++i)
         {
             ScopedContextPath subPath(context, i);
 
             void* element = container->GetElementByIndex(outputValue, nullptr, i);
-            JSR::ResultCode result = ContinueLoading(element, elementTypeId, inputValue[aznumeric_caster(i)], context, flags);
+            JSR::ResultCode result = ContinueLoading(
+                element, elementTypeId, isNewInstance ? explicitDefaultValue : inputValue[aznumeric_caster(i)], context, flags);
             if (result.GetProcessing() == JSR::Processing::Halted)
             {
                 return context.Report(result, "Failed to load data to element in AZStd::array.");
@@ -189,15 +212,19 @@ namespace AZ
             retVal.Combine(result);
         }
 
-        if (container->Size(outputValue) == inputValue.Size())
+        if (isNewInstance)
+        {
+            return context.Report(retVal, "Filled new instance of AZStd::array with defaults.");
+        }
+        else if (container->Size(outputValue) == inputValue.Size())
         {
             return context.Report(retVal, "Successfully read entries into AZStd::array.");
         }
         else
         {
             retVal.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Skipped));
-            return context.Report(retVal,
-                "Successfully read available entries into AZStd::array, but there were still values left in the JSON array.");
+            return context.Report(
+                retVal, "Successfully read available entries into AZStd::array, but there were still values left in the JSON array.");
         }
     }
 } // namespace AZ

+ 7 - 1
Code/Framework/AzCore/AzCore/Serialization/Json/ArraySerializer.h

@@ -30,8 +30,14 @@ namespace AZ
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
 
+        OperationFlags GetOperationsFlags() const override;
+
     protected:
-        JsonSerializationResult::Result LoadContainer(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+        JsonSerializationResult::Result LoadContainer(
+            void* outputValue,
+            const Uuid& outputValueTypeId,
+            const rapidjson::Value& inputValue,
+            bool isNewInstance,
             JsonDeserializerContext& context);
     };
 } // namespace AZ

+ 2 - 1
Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.cpp

@@ -216,9 +216,10 @@ namespace AZ
     JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoading(
         void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context, ContinuationFlags flags)
     {
+        bool loadAsNewInstance = (flags & ContinuationFlags::LoadAsNewInstance) == ContinuationFlags::LoadAsNewInstance;
         return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer
             ? JsonDeserializer::LoadToPointer(object, typeId, value, context)
-            : JsonDeserializer::Load(object, typeId, value, context);
+            : JsonDeserializer::Load(object, typeId, value, loadAsNewInstance, context);
     }
 
     JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring(

+ 10 - 5
Code/Framework/AzCore/AzCore/Serialization/Json/BaseJsonSerializer.h

@@ -163,15 +163,20 @@ namespace AZ
         
         enum class ContinuationFlags
         {
-            None = 0,                //! No extra flags.
-            ResolvePointer = 1 << 0, //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance.
-            ReplaceDefault = 1 << 1  //! The default value provided for storing will be replaced with a newly created one.
+            None = 0,                   //! No extra flags.
+            ResolvePointer = 1 << 0,    //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance.
+            ReplaceDefault = 1 << 1,    //! The default value provided for storing will be replaced with a newly created one.
+            LoadAsNewInstance = 1 << 2  //! Treats the value as if it's a newly created instance. This may trigger serializers marked with
+                                        //! OperationFlags::InitializeNewInstance. Used for instance by pointers or new instances added to
+                                        //! an array.
         };
 
         enum class OperationFlags
         {
-            None = 0,               //! No flags that control how the custom json serializer is used.
-            ManualDefault = 1 << 0  //! Even if an (explicit) default is found the custom json serializer will still be called.
+            None = 0,                       //! No flags that control how the custom json serializer is used.
+            ManualDefault = 1 << 0,         //! Even if an (explicit) default is found the custom json serializer will still be called.
+            InitializeNewInstance = 1 << 1  //! If set, the custom json serializer will be called with an explicit default if a new
+                                            //! instance of its target type is created.
         };
 
         virtual ~BaseJsonSerializer() = default;

+ 20 - 5
Code/Framework/AzCore/AzCore/Serialization/Json/BasicContainerSerializer.cpp

@@ -34,11 +34,16 @@ namespace AZ
         case rapidjson::kArrayType:
             return LoadContainer(outputValue, outputValueTypeId, inputValue, context);
 
-        case rapidjson::kObjectType: // fall through
-        case rapidjson::kNullType: // fall through
-        case rapidjson::kStringType: // fall through
-        case rapidjson::kFalseType: // fall through
-        case rapidjson::kTrueType: // fall through
+        case rapidjson::kObjectType:
+            [[fallthrough]];
+        case rapidjson::kNullType:
+            [[fallthrough]];
+        case rapidjson::kStringType:
+            [[fallthrough]];
+        case rapidjson::kFalseType:
+            [[fallthrough]];
+        case rapidjson::kTrueType:
+            [[fallthrough]];
         case rapidjson::kNumberType:
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                 "Unsupported type. Basic containers can only be read from an array.");
@@ -123,6 +128,10 @@ namespace AZ
         {
             if (retVal.HasDoneWork())
             {
+                // If at least one value was written, even if it has all defaults, then the array has
+                // a value written to it and is therefore not in a default state anymore.
+                retVal.Combine(JSR::ResultCode(JSR::Tasks::WriteValue, JSR::Outcomes::Success));
+
                 outputValue = AZStd::move(array);
                 return context.Report(retVal, "Content written to basic container.");
             }
@@ -165,6 +174,7 @@ namespace AZ
         ContinuationFlags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
             ? ContinuationFlags::ResolvePointer
             : ContinuationFlags::None;
+        flags |= ContinuationFlags::LoadAsNewInstance;
 
         const size_t capacity = container->IsFixedCapacity() ? container->Capacity(outputValue) : std::numeric_limits<size_t>::max();
 
@@ -243,6 +253,11 @@ namespace AZ
         }
 
         size_t addedCount = container->Size(outputValue) - containerSize;
+        if (addedCount > 0)
+        {
+            // Values were added which means the container is no longer in its default state of being empty.
+            retVal.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Success));
+        }
         AZStd::string_view message =
             addedCount >= arraySize ? "Successfully read basic container.":
             addedCount == 0 ? "Unable to read data for basic container." :

+ 14 - 3
Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.cpp

@@ -82,12 +82,18 @@ namespace AZ
 
         bool* valAsBool = reinterpret_cast<bool*>(outputValue);
 
+        if (IsExplicitDefault(inputValue))
+        {
+            *valAsBool = {};
+            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Boolean value set to default of 'false'.");
+        }
+
         switch (inputValue.GetType())
         {
         case rapidjson::kArrayType:
-        // fallthrough
+            [[fallthrough]];
         case rapidjson::kObjectType:
-        // fallthrough
+            [[fallthrough]];
         case rapidjson::kNullType:
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                 "Unsupported type. Booleans can't be read from arrays, objects or null.");
@@ -96,7 +102,7 @@ namespace AZ
             return SerializerInternal::TextToValue(valAsBool, inputValue.GetString(), inputValue.GetStringLength(), context);
 
         case rapidjson::kFalseType:
-        // fallthrough
+            [[fallthrough]];
         case rapidjson::kTrueType:
             *valAsBool = inputValue.GetBool();
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read boolean.");
@@ -145,4 +151,9 @@ namespace AZ
         
         return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "Default boolean used.");
     }
+
+    auto JsonBoolSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
 } // namespace AZ

+ 1 - 0
Code/Framework/AzCore/AzCore/Serialization/Json/BoolSerializer.h

@@ -27,5 +27,6 @@ namespace AZ
             JsonDeserializerContext& context) override;
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
+        OperationFlags GetOperationsFlags() const override;
     };
 } // namespace AZ

+ 25 - 6
Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.cpp

@@ -62,19 +62,26 @@ namespace AZ
         }
 
         template <typename T>
-        static JsonSerializationResult::Result Load(T* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+        static JsonSerializationResult::Result Load(
+            T* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context, bool isExplicitDefault)
         {
             namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
 
             static_assert(AZStd::is_floating_point<T>::value, "Expected T to be a floating point type");
             AZ_Assert(outputValue, "Expected a valid pointer to load from json value.");
 
+            if (isExplicitDefault)
+            {
+                *outputValue = {};
+                return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Floating point value set to default of 0.0.");
+            }
+
             switch (inputValue.GetType())
             {
             case rapidjson::kArrayType:
-            // fallthrough
+                [[fallthrough]];
             case rapidjson::kObjectType:
-            // fallthrough
+                [[fallthrough]];
             case rapidjson::kNullType:
                 return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                     "Unsupported type. Floating point values can't be read from arrays, objects or null.");
@@ -83,7 +90,7 @@ namespace AZ
                 return TextToValue(outputValue, inputValue.GetString(), context);
 
             case rapidjson::kFalseType:
-            // fallthrough
+                [[fallthrough]];
             case rapidjson::kTrueType:
                 *outputValue = inputValue.GetBool() ? 1.0f : 0.0f;
                 return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success,
@@ -144,7 +151,8 @@ namespace AZ
             "Unable to deserialize double to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerFloatingPointInternal::Load(reinterpret_cast<double*>(outputValue), inputValue, context);
+        return SerializerFloatingPointInternal::Load(
+            reinterpret_cast<double*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonDoubleSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -156,6 +164,11 @@ namespace AZ
         return SerializerFloatingPointInternal::Store<double>(outputValue, inputValue, defaultValue, context);
     }
 
+    auto JsonDoubleSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
     JsonSerializationResult::Result JsonFloatSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
         JsonDeserializerContext& context)
     {
@@ -163,7 +176,8 @@ namespace AZ
             "Unable to deserialize float to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerFloatingPointInternal::Load(reinterpret_cast<float*>(outputValue), inputValue, context);
+        return SerializerFloatingPointInternal::Load(
+            reinterpret_cast<float*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonFloatSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -174,4 +188,9 @@ namespace AZ
         AZ_UNUSED(valueTypeId);
         return SerializerFloatingPointInternal::Store<float>(outputValue, inputValue, defaultValue, context);
     }
+
+    auto JsonFloatSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
 } // namespace AZ

+ 2 - 0
Code/Framework/AzCore/AzCore/Serialization/Json/DoubleSerializer.h

@@ -28,6 +28,7 @@ namespace AZ
             JsonDeserializerContext& context) override;
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue,  const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
+        OperationFlags GetOperationsFlags() const override;
     };
 
     class JsonFloatSerializer
@@ -40,5 +41,6 @@ namespace AZ
             JsonDeserializerContext& context) override;
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
+        OperationFlags GetOperationsFlags() const override;
     };
 } // namespace AZ

+ 32 - 14
Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.cpp

@@ -25,6 +25,8 @@
 
 namespace AZ
 {
+    AZ_CLASS_ALLOCATOR_IMPL(BaseJsonIntegerSerializer, SystemAllocator, 0);
+
     AZ_CLASS_ALLOCATOR_IMPL(JsonCharSerializer, SystemAllocator, 0);
     AZ_CLASS_ALLOCATOR_IMPL(JsonShortSerializer, SystemAllocator, 0);
     AZ_CLASS_ALLOCATOR_IMPL(JsonIntSerializer, SystemAllocator, 0);
@@ -56,19 +58,25 @@ namespace AZ
 
         template <typename T>
         static JsonSerializationResult::Result LoadInt(T* outputValue, const rapidjson::Value& inputValue,
-            JsonDeserializerContext& context)
+            JsonDeserializerContext& context, bool isDefaultValue)
         {
             namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
 
             static_assert(AZStd::is_integral<T>(), "Expected T to be a signed or unsigned type");
             AZ_Assert(outputValue, "Expected a valid pointer to load from json value.");
 
+            if (isDefaultValue)
+            {
+                *outputValue = {};
+                return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Integer value set to default of zero.");
+            }
+
             switch (inputValue.GetType())
             {
             case rapidjson::kArrayType:
-            // fallthrough
+                [[fallthrough]];
             case rapidjson::kObjectType:
-            // fallthrough
+                [[fallthrough]];
             case rapidjson::kNullType:
                 return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                     "Unsupported type. Integers can't be read from arrays, objects or null.");
@@ -77,7 +85,7 @@ namespace AZ
                 return TextToValue(outputValue, inputValue.GetString(), context);
 
             case rapidjson::kFalseType:
-            // fallthrough
+                [[fallthrough]];
             case rapidjson::kTrueType:
                 *outputValue = inputValue.GetBool() ? 1 : 0;
                 return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success,
@@ -125,6 +133,11 @@ namespace AZ
         }
     } // namespace SerializerInternal
 
+    auto BaseJsonIntegerSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
     JsonSerializationResult::Result JsonCharSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
         JsonDeserializerContext& context)
     {
@@ -132,7 +145,7 @@ namespace AZ
             "Unable to deserialize char to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<char*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(reinterpret_cast<char*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonCharSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
@@ -151,7 +164,7 @@ namespace AZ
             "Unable to deserialize short to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<short*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(reinterpret_cast<short*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonShortSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
@@ -170,7 +183,7 @@ namespace AZ
             "Unable to deserialize int to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<int*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(reinterpret_cast<int*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonIntSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
@@ -189,7 +202,7 @@ namespace AZ
             "Unable to deserialize long to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<long*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(reinterpret_cast<long*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
@@ -208,7 +221,7 @@ namespace AZ
             "Unable to deserialize long long to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<long long*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(reinterpret_cast<long long*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonLongLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
@@ -227,7 +240,8 @@ namespace AZ
             "Unable to deserialize unsigned char to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<unsigned char*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(
+            reinterpret_cast<unsigned char*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonUnsignedCharSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -246,7 +260,8 @@ namespace AZ
             "Unable to deserialize unsigned short to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<unsigned short*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(
+            reinterpret_cast<unsigned short*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonUnsignedShortSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -265,7 +280,8 @@ namespace AZ
             "Unable to deserialize unsigned int to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<unsigned int*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(
+            reinterpret_cast<unsigned int*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonUnsignedIntSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -284,7 +300,8 @@ namespace AZ
             "Unable to deserialize unsigned long to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<unsigned long*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(
+            reinterpret_cast<unsigned long*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonUnsignedLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,
@@ -303,7 +320,8 @@ namespace AZ
             "Unable to deserialize unsigned long long to json because the provided type is %s",
             outputValueTypeId.ToString<AZStd::string>().c_str());
         AZ_UNUSED(outputValueTypeId);
-        return SerializerInternal::LoadInt(reinterpret_cast<unsigned long long*>(outputValue), inputValue, context);
+        return SerializerInternal::LoadInt(
+            reinterpret_cast<unsigned long long*>(outputValue), inputValue, context, IsExplicitDefault(inputValue));
     }
 
     JsonSerializationResult::Result JsonUnsignedLongLongSerializer::Store(rapidjson::Value& outputValue, const void* inputValue,

+ 28 - 30
Code/Framework/AzCore/AzCore/Serialization/Json/IntSerializer.h

@@ -18,11 +18,18 @@
 
 namespace AZ
 {
-    class JsonCharSerializer
-        : public BaseJsonSerializer
+    class BaseJsonIntegerSerializer : public BaseJsonSerializer
     {
     public:
-        AZ_RTTI(JsonCharSerializer, "{CA2A4AAC-3068-40B2-94F8-A537FBA8236E}", BaseJsonSerializer);
+        AZ_RTTI(BaseJsonIntegerSerializer, "{FD060F54-D3B5-4D5B-B64A-AFE371CD6F20}", BaseJsonSerializer);
+        AZ_CLASS_ALLOCATOR_DECL;
+        OperationFlags GetOperationsFlags() const override;
+    };
+
+    class JsonCharSerializer : public BaseJsonIntegerSerializer
+    {
+    public:
+        AZ_RTTI(JsonCharSerializer, "{CA2A4AAC-3068-40B2-94F8-A537FBA8236E}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -30,11 +37,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonShortSerializer
-        : public BaseJsonSerializer
+    class JsonShortSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonShortSerializer, "{3D6789BD-231B-4E5D-B81D-609E71A2BCB5}", BaseJsonSerializer);
+        AZ_RTTI(JsonShortSerializer, "{3D6789BD-231B-4E5D-B81D-609E71A2BCB5}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -42,11 +48,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonIntSerializer
-        : public BaseJsonSerializer
+    class JsonIntSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonIntSerializer, "{29E26946-0F1F-44B0-A098-1171B7B0C8FA}", BaseJsonSerializer);
+        AZ_RTTI(JsonIntSerializer, "{29E26946-0F1F-44B0-A098-1171B7B0C8FA}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -54,11 +59,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonLongSerializer
-        : public BaseJsonSerializer
+    class JsonLongSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonLongSerializer, "{0EB432D0-A0C8-43B2-9D65-A73A4D6DFE3E}", BaseJsonSerializer);
+        AZ_RTTI(JsonLongSerializer, "{0EB432D0-A0C8-43B2-9D65-A73A4D6DFE3E}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -66,11 +70,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonLongLongSerializer
-        : public BaseJsonSerializer
+    class JsonLongLongSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonLongLongSerializer, "{5E7967DE-A4DC-40E1-81A1-2896A054BB8A}", BaseJsonSerializer);
+        AZ_RTTI(JsonLongLongSerializer, "{5E7967DE-A4DC-40E1-81A1-2896A054BB8A}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -78,11 +81,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
     
-    class JsonUnsignedCharSerializer
-        : public BaseJsonSerializer
+    class JsonUnsignedCharSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonUnsignedCharSerializer, "{1E6D606F-8490-4736-AAFF-91046FDEA2BB}", BaseJsonSerializer);
+        AZ_RTTI(JsonUnsignedCharSerializer, "{1E6D606F-8490-4736-AAFF-91046FDEA2BB}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -90,11 +92,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonUnsignedShortSerializer
-        : public BaseJsonSerializer
+    class JsonUnsignedShortSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonUnsignedShortSerializer, "{3C92D2CC-CB13-4A40-B779-47562EE36451}", BaseJsonSerializer);
+        AZ_RTTI(JsonUnsignedShortSerializer, "{3C92D2CC-CB13-4A40-B779-47562EE36451}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -102,11 +103,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonUnsignedIntSerializer
-        : public BaseJsonSerializer
+    class JsonUnsignedIntSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonUnsignedIntSerializer, "{70C0714A-690D-4F30-8986-ABC9DEFE9D62}", BaseJsonSerializer);
+        AZ_RTTI(JsonUnsignedIntSerializer, "{70C0714A-690D-4F30-8986-ABC9DEFE9D62}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -114,11 +114,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
 
-    class JsonUnsignedLongSerializer
-        : public BaseJsonSerializer
+    class JsonUnsignedLongSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonUnsignedLongSerializer, "{28E5499F-6AF4-4778-AE14-66BA40B56247}", BaseJsonSerializer);
+        AZ_RTTI(JsonUnsignedLongSerializer, "{28E5499F-6AF4-4778-AE14-66BA40B56247}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
@@ -126,11 +125,10 @@ namespace AZ
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
     };
     
-    class JsonUnsignedLongLongSerializer
-        : public BaseJsonSerializer
+    class JsonUnsignedLongLongSerializer : public BaseJsonIntegerSerializer
     {
     public:
-        AZ_RTTI(JsonUnsignedLongLongSerializer, "{AB048BB3-C280-4166-9E2E-54CE2C3413CA}", BaseJsonSerializer);
+        AZ_RTTI(JsonUnsignedLongLongSerializer, "{AB048BB3-C280-4166-9E2E-54CE2C3413CA}", BaseJsonIntegerSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;

+ 16 - 9
Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.cpp

@@ -19,25 +19,30 @@
 #include <AzCore/Serialization/Json/RegistrationContext.h>
 #include <AzCore/Serialization/Json/StackedString.h>
 #include <AzCore/std/string/conversions.h>
+#include <AzCore/std/string/fixed_string.h>
 #include <AzCore/std/string/string.h>
 
 namespace AZ
 {
     JsonSerializationResult::ResultCode JsonDeserializer::DeserializerDefaultCheck(BaseJsonSerializer* serializer, void* object,
-        const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context)
+        const Uuid& typeId,const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context)
     {
         using namespace AZ::JsonSerializationResult;
 
         bool isExplicitDefault = IsExplicitDefault(value);
         bool manuallyDefaults = (serializer->GetOperationsFlags() & BaseJsonSerializer::OperationFlags::ManualDefault) ==
             BaseJsonSerializer::OperationFlags::ManualDefault;
-        return !isExplicitDefault || (isExplicitDefault && manuallyDefaults)
+        bool initializeNewInstance = (serializer->GetOperationsFlags() & BaseJsonSerializer::OperationFlags::InitializeNewInstance) ==
+            BaseJsonSerializer::OperationFlags::InitializeNewInstance;
+
+        return
+            !isExplicitDefault || (isExplicitDefault && manuallyDefaults) || (isExplicitDefault && isNewInstance && initializeNewInstance)
             ? serializer->Load(object, typeId, value, context)
             : context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
     }
 
-    JsonSerializationResult::ResultCode JsonDeserializer::Load(void* object, const Uuid& typeId, const rapidjson::Value& value,
-        JsonDeserializerContext& context)
+    JsonSerializationResult::ResultCode JsonDeserializer::Load(
+        void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context)
     {
         using namespace AZ::JsonSerializationResult;
 
@@ -50,7 +55,7 @@ namespace AZ
         BaseJsonSerializer* serializer = context.GetRegistrationContext()->GetSerializerForType(typeId);
         if (serializer)
         {
-            return DeserializerDefaultCheck(serializer, object, typeId, value, context);
+            return DeserializerDefaultCheck(serializer, object, typeId, value, isNewInstance, context);
         }
 
         const SerializeContext::ClassData* classData = context.GetSerializeContext()->FindClassData(typeId);
@@ -72,7 +77,7 @@ namespace AZ
             serializer = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId());
             if (serializer)
             {
-                return DeserializerDefaultCheck(serializer, object, typeId, value, context);
+                return DeserializerDefaultCheck(serializer, object, typeId, value, isNewInstance, context);
             }
         }
 
@@ -133,7 +138,7 @@ namespace AZ
             const SerializeContext::ClassData* resolvedClassData = context.GetSerializeContext()->FindClassData(resolvedTypeId);
             if (resolvedClassData)
             {
-                status = JsonDeserializer::Load(*objectPtr, resolvedTypeId, value, context);
+                status = JsonDeserializer::Load(*objectPtr, resolvedTypeId, value, true, context);
 
                 *objectPtr = resolvedClassData->m_azRtti->Cast(*objectPtr, typeId);
 
@@ -174,7 +179,7 @@ namespace AZ
         }
         else
         {
-            return Load(object, classElement.m_typeId, value, context);
+            return Load(object, classElement.m_typeId, value, false, context);
         }
     }
 
@@ -591,7 +596,9 @@ namespace AZ
                 }
                 else
                 {
-                    status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown, "Serialization information for target type not found.");
+                    using ReporterString = AZStd::fixed_string<1024>;
+                    status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
+                        ReporterString::format("Serialization information for target type %s not found.", loadedTypeId.m_typeId.ToString<ReporterString>().c_str()));
                     return ResolvePointerResult::FullyProcessed;
                 }
                 objectType = loadedTypeId.m_typeId;

+ 3 - 2
Code/Framework/AzCore/AzCore/Serialization/Json/JsonDeserializer.h

@@ -58,8 +58,8 @@ namespace AZ
         JsonDeserializer(const JsonDeserializer& rhs) = delete;
         JsonDeserializer(JsonDeserializer&& rhs) = delete;
 
-        static JsonSerializationResult::ResultCode Load(void* object, const Uuid& typeId, const rapidjson::Value& value,
-            JsonDeserializerContext& context);
+        static JsonSerializationResult::ResultCode Load(
+            void* object, const Uuid& typeId, const rapidjson::Value& value, bool isNewInstance, JsonDeserializerContext& context);
 
         static JsonSerializationResult::ResultCode LoadToPointer(void* object, const Uuid& typeId, const rapidjson::Value& value,
             JsonDeserializerContext& context);
@@ -120,6 +120,7 @@ namespace AZ
             void* object,
             const Uuid& typeId,
             const rapidjson::Value& value,
+            bool isNewInstance,
             JsonDeserializerContext& context);
     };
 } // namespace AZ

+ 5 - 3
Code/Framework/AzCore/AzCore/Serialization/Json/JsonMerger.cpp

@@ -607,10 +607,12 @@ namespace AZ
             }
             else if (source.Size() > target.Size())
             {
-                rapidjson::SizeType sourceCount = source.Size();
-                for (rapidjson::SizeType i = count; i < sourceCount; ++i)
+                // Loop backwards through the removals so that each removal has a valid index when processing in order.
+                for (rapidjson::SizeType i = source.Size(); i > count; --i)
                 {
-                    ScopedStackedString entryName(element, i);
+                    // (We use "i - 1" here instead of in the loop to ensure we don't wrap around our unsigned numbers in the case
+                    // where count is 0.)
+                    ScopedStackedString entryName(element, i - 1);
                     patch.PushBack(CreatePatchInternal_Remove(allocator, element), allocator);
                     resultCode.Combine(settings.m_reporting("Removed member from array in JSON Patch.",
                         ResultCode(Tasks::CreatePatch, Outcomes::Success), element));

+ 1 - 1
Code/Framework/AzCore/AzCore/Serialization/Json/JsonSerialization.cpp

@@ -249,7 +249,7 @@ namespace AZ
         {
             StackedString path(StackedString::Format::JsonPointer);
             JsonDeserializerContext context(settings);
-            result = JsonDeserializer::Load(object, objectType, root, context);
+            result = JsonDeserializer::Load(object, objectType, root, false, context);
         }
         return result;
     }

+ 10 - 4
Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.cpp

@@ -190,6 +190,12 @@ namespace AZ
         }
 
         size_t addedCount = container->Size(outputValue) - containerSize;
+        if (addedCount > 0)
+        {
+            // If at least one entry was added then the map is no longer in it's default state so
+            // mark is with success so the result can at best be partial defaults.
+            retVal.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Success));
+        }
         AZStd::string_view message =
             addedCount >= maximumSize ? "Successfully read associative container." :
             addedCount == 0 ? "Unable to read data for the associative container." : 
@@ -215,10 +221,10 @@ namespace AZ
         // Load key
         void* keyAddress = pairContainer->GetElementByIndex(address, pairElement, 0);
         AZ_Assert(keyAddress, "Element reserved for associative container, but unable to retrieve address of the key.");
-        ContinuationFlags keyLoadFlags = ContinuationFlags::None;
+        ContinuationFlags keyLoadFlags = ContinuationFlags::LoadAsNewInstance;
         if (keyElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
         {
-            keyLoadFlags = ContinuationFlags::ResolvePointer;
+            keyLoadFlags |= ContinuationFlags::ResolvePointer;
             *reinterpret_cast<void**>(keyAddress) = nullptr;
         }
         JSR::ResultCode keyResult = ContinueLoading(keyAddress, keyElement->m_typeId, key, context, keyLoadFlags);
@@ -231,10 +237,10 @@ namespace AZ
         // Load value
         void* valueAddress = pairContainer->GetElementByIndex(address, pairElement, 1);
         AZ_Assert(valueAddress, "Element reserved for associative container, but unable to retrieve address of the value.");
-        ContinuationFlags valueLoadFlags = ContinuationFlags::None; 
+        ContinuationFlags valueLoadFlags = ContinuationFlags::LoadAsNewInstance; 
         if (valueElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
         {
-            valueLoadFlags = ContinuationFlags::ResolvePointer;
+            valueLoadFlags |= ContinuationFlags::ResolvePointer;
             *reinterpret_cast<void**>(valueAddress) = nullptr;
         }
         JSR::ResultCode valueResult = ContinueLoading(valueAddress, valueElement->m_typeId, value, context, valueLoadFlags);

+ 84 - 41
Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.cpp

@@ -34,13 +34,24 @@ namespace AZ
         switch (inputValue.GetType())
         {
         case rapidjson::kArrayType:
-            return LoadContainer(outputValue, outputValueTypeId, inputValue, context);
+            return LoadContainer(outputValue, outputValueTypeId, inputValue, false, context);
         
-        case rapidjson::kObjectType: // fall through
-        case rapidjson::kNullType: // fall through
-        case rapidjson::kStringType: // fall through
-        case rapidjson::kFalseType: // fall through
-        case rapidjson::kTrueType: // fall through
+        case rapidjson::kObjectType:
+            if (IsExplicitDefault(inputValue))
+            {
+                // Because this serializer has only the operation flag "InitializeNewInstance" set, the only time this will be called with
+                // an explicit default is when a new instance has been created.
+                return LoadContainer(outputValue, outputValueTypeId, inputValue, true, context);
+            }
+            [[fallthrough]];
+        case rapidjson::kNullType:
+            [[fallthrough]];
+        case rapidjson::kStringType:
+            [[fallthrough]];
+        case rapidjson::kFalseType:
+            [[fallthrough]];
+        case rapidjson::kTrueType:
+            [[fallthrough]];
         case rapidjson::kNumberType:
             return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
                 "Unsupported type. AZStd::pair or AZStd::tuple can only be read from an array.");
@@ -127,8 +138,13 @@ namespace AZ
         }
     }
 
+    auto JsonTupleSerializer::GetOperationsFlags() const -> OperationFlags
+    {
+        return OperationFlags::InitializeNewInstance;
+    }
+
     JsonSerializationResult::Result JsonTupleSerializer::LoadContainer(void* outputValue, const Uuid& outputValueTypeId,
-        const rapidjson::Value& inputValue, JsonDeserializerContext& context)
+        const rapidjson::Value& inputValue, bool isNewInstance, JsonDeserializerContext& context)
     {
         namespace JSR = JsonSerializationResult; // Used to remove name conflicts in AzCore in uber builds.
 
@@ -154,13 +170,6 @@ namespace AZ
         };
         container->EnumTypes(typeCountCallback);
 
-        rapidjson::SizeType arraySize = inputValue.Size();
-        if (arraySize < typeCount)
-        {
-            return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
-                "Not enough entries in array to load an AZStd::pair or AZStd::tuple from.");
-        }
-
         AZStd::vector<const SerializeContext::ClassElement*> classElements;
         classElements.reserve(typeCount);
         auto typeEnumCallback = [&classElements](const Uuid&, const SerializeContext::ClassElement* genericClassElement)
@@ -171,46 +180,80 @@ namespace AZ
         container->EnumTypes(typeEnumCallback);
 
         JSR::ResultCode retVal(JSR::Tasks::ReadField);
-        rapidjson::SizeType arrayIndex = 0;
-        size_t numElementsWritten = 0;
-        for (size_t i = 0; i < typeCount; ++i)
+        if (isNewInstance)
         {
-            ScopedContextPath subPath(context, i);
-            
-            void* elementAddress = container->GetElementByIndex(outputValue, nullptr, i);
-            AZ_Assert(elementAddress, "Address of AZStd::pair or AZStd::tuple element %zu could not be retrieved.", i);
-
-            ContinuationFlags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
-                ? ContinuationFlags::ResolvePointer
-                : ContinuationFlags::None;
+            rapidjson::Value explicitDefaultValue = GetExplicitDefault();
 
-            while (arrayIndex < inputValue.Size())
+            for (size_t i = 0; i < typeCount; ++i)
             {
-                JSR::ResultCode result = ContinueLoading(elementAddress, classElements[i]->m_typeId, inputValue[arrayIndex], context, flags);
+                ScopedContextPath subPath(context, i);
+
+                void* elementAddress = container->GetElementByIndex(outputValue, nullptr, i);
+                AZ_Assert(elementAddress, "Address of AZStd::pair or AZStd::tuple element %zu could not be retrieved.", i);
+
+                ContinuationFlags flags = ContinuationFlags::LoadAsNewInstance;
+                flags |=
+                    (classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ? ContinuationFlags::ResolvePointer
+                                                                                                    : ContinuationFlags::None);
+                JSR::ResultCode result = ContinueLoading(elementAddress, classElements[i]->m_typeId, explicitDefaultValue, context, flags);
                 retVal.Combine(result);
-                arrayIndex++;
                 if (result.GetProcessing() == JSR::Processing::Halted)
                 {
                     return context.Report(retVal, "Failed to read element for AZStd::pair or AZStd::tuple.");
                 }
-                else if (result.GetProcessing() != JSR::Processing::Altered)
-                {
-                    numElementsWritten++;
-                    break;
-                }
             }
-        }
 
-        if (numElementsWritten < typeCount)
-        {
-            AZStd::string_view message = numElementsWritten == 0 ?
-                "Unable to read data for AZStd::pair or AZStd::tuple." :
-                "Partially read data for AZStd::pair or AZStd::tuple.";
-            return context.Report(retVal, message);
+            return context.Report(retVal, "Initialized AZStd::pair or AZStd::tuple to defaults.");
         }
         else
         {
-            return context.Report(retVal, "Successfully read AZStd::pair or AZStd::tuple.");
+            if (inputValue.Size() < typeCount)
+            {
+                return context.Report(
+                    JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
+                    "Not enough entries in array to load an AZStd::pair or AZStd::tuple from.");
+            }
+
+            rapidjson::SizeType arrayIndex = 0;
+            size_t numElementsWritten = 0;
+            for (size_t i = 0; i < typeCount; ++i)
+            {
+                ScopedContextPath subPath(context, i);
+
+                void* elementAddress = container->GetElementByIndex(outputValue, nullptr, i);
+                AZ_Assert(elementAddress, "Address of AZStd::pair or AZStd::tuple element %zu could not be retrieved.", i);
+
+                ContinuationFlags flags =
+                    (classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ? ContinuationFlags::ResolvePointer
+                                                                                                    : ContinuationFlags::None);
+                while (arrayIndex < inputValue.Size())
+                {
+                    JSR::ResultCode result =
+                        ContinueLoading(elementAddress, classElements[i]->m_typeId, inputValue[arrayIndex], context, flags);
+                    retVal.Combine(result);
+                    arrayIndex++;
+                    if (result.GetProcessing() == JSR::Processing::Halted)
+                    {
+                        return context.Report(retVal, "Failed to read element for AZStd::pair or AZStd::tuple.");
+                    }
+                    else if (result.GetProcessing() != JSR::Processing::Altered)
+                    {
+                        numElementsWritten++;
+                        break;
+                    }
+                }
+            }
+
+            if (numElementsWritten < typeCount)
+            {
+                AZStd::string_view message = numElementsWritten == 0 ? "Unable to read data for AZStd::pair or AZStd::tuple."
+                                                                     : "Partially read data for AZStd::pair or AZStd::tuple.";
+                return context.Report(retVal, message);
+            }
+            else
+            {
+                return context.Report(retVal, "Successfully read AZStd::pair or AZStd::tuple.");
+            }
         }
     }
 } // namespace AZ

+ 8 - 1
Code/Framework/AzCore/AzCore/Serialization/Json/TupleSerializer.h

@@ -23,13 +23,20 @@ namespace AZ
     public:
         AZ_RTTI(JsonTupleSerializer, "{1AA0ADC1-395A-4223-8A73-304ACDEE7793}", BaseJsonSerializer);
         AZ_CLASS_ALLOCATOR_DECL;
+
         JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
             JsonDeserializerContext& context) override;
         JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
             const Uuid& valueTypeId, JsonSerializerContext& context) override;
 
+        OperationFlags GetOperationsFlags() const override;
+
     private:
-        JsonSerializationResult::Result LoadContainer(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
+        JsonSerializationResult::Result LoadContainer(
+            void* outputValue,
+            const Uuid& outputValueTypeId,
+            const rapidjson::Value& inputValue,
+            bool isNewInstance,
             JsonDeserializerContext& context);
     };
 } // namespace AZ

+ 6 - 2
Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp

@@ -816,7 +816,11 @@ namespace AZ::SettingsRegistryMergeUtils
         }
     }
 
-    void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine, bool executeCommands)
+    // This function intentionally copies `commandLine`. It looks like it only uses it as a const reference, but the
+    // code in the loop makes calls that mutates the `commandLine` instance, invalidating the iterators. Making a copy
+    // ensures that the iterators remain valid.
+    // NOLINTNEXTLINE(performance-unnecessary-value-param)
+    void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, AZ::CommandLine commandLine, bool executeCommands)
     {
         // Iterate over all the command line options in order to parse the --regset and --regremove
         // arguments in the order they were supplied
@@ -831,7 +835,7 @@ namespace AZ::SettingsRegistryMergeUtils
                     continue;
                 }
             }
-            if (commandArgument.m_option == "regremove")
+            else if (commandArgument.m_option == "regremove")
             {
                 if (!registry.Remove(commandArgument.m_value))
                 {

+ 2 - 6
Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h

@@ -15,11 +15,7 @@
 #include <AzCore/IO/Path/Path_fwd.h>
 #include <AzCore/Memory/OSAllocator.h>
 #include <AzCore/Settings/SettingsRegistry.h>
-
-namespace AZ
-{
-    class CommandLine;
-}
+#include <AzCore/Settings/CommandLine.h>
 
 namespace AZ::IO
 {
@@ -217,7 +213,7 @@ namespace AZ::SettingsRegistryMergeUtils
     //!     example: --regdump /My/Array/With/Objects
     //! --regdumpall Dumps the entire settings registry to output.
     //! Note that this function is only called in development builds and is compiled out in release builds.
-    void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, const AZ::CommandLine& commandLine, bool executeCommands);
+    void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, AZ::CommandLine commandLine, bool executeCommands);
 
     //! Stores the command line settings into the Setting Registry
     //! The arguments can be used later anywhere the command line is needed

+ 4 - 0
Code/Framework/AzCore/Tests/AssetJsonSerializerTests.cpp

@@ -168,6 +168,10 @@ namespace JsonSerializationTests
         {
             features.EnableJsonType(rapidjson::kObjectType);
             features.m_typeToInject = rapidjson::kNullType;
+            // Assets are not fully registered with the Serialize Context for historical reasons. Due to the missing
+            // information the Json Serializer Conformity Tests can't run the subsection of tests that explicitly
+            // require the missing information.
+            features.m_enableNewInstanceTests = false;
         }
 
         bool AreEqual(const Asset& lhs, const Asset& rhs) override

+ 5 - 0
Code/Framework/AzCore/Tests/Name/NameJsonSerializerTests.cpp

@@ -32,6 +32,11 @@ namespace JsonSerializationTests
             AZ::NameDictionary::Destroy();
         }
 
+        void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context)
+        {
+            AZ::Name::Reflect(context.get());
+        }
+
         void Reflect(AZStd::unique_ptr<AZ::JsonRegistrationContext>& context)
         {
             AZ::Name::Reflect(context.get());

+ 17 - 46
Code/Framework/AzCore/Tests/Serialization/Json/ArraySerializerTests.cpp

@@ -126,9 +126,9 @@ namespace JsonSerializationTests
         {
             auto array = AZStd::shared_ptr<Array>(new Array(), Deleter);
             (*array)[0] = nullptr;
-            (*array)[1] = aznew MultipleInheritence();
+            (*array)[1] = nullptr;
             (*array)[2] = nullptr;
-            (*array)[3] = aznew MultipleInheritence();
+            (*array)[3] = nullptr;
             return array;
         }
 
@@ -154,6 +154,7 @@ namespace JsonSerializationTests
                 null,
                 null,
                 {
+                    "$type": "MultipleInheritence",
                     "base_var": 242.0,
                     "var1" : 142
                 }
@@ -246,56 +247,21 @@ namespace JsonSerializationTests
             ])";
         }
 
-        AZStd::string_view GetJsonFor_Store_SerializeFullySetInstance() override
-        {
-            // This is a unique situation because the $type is determined separate from other values, so all
-            // member values can be changed, but since the default type matches the stored type the $type
-            // will only be written if default values are explicitly kept.
-            return R"(
-            [
-                {
-                    "$type": "MultipleInheritence",
-                    "base_var": 1142.0,
-                    "base2_var1": 1242.0,
-                    "base2_var2": 1342.0,
-                    "base2_var3": 1442.0,
-                    "var1" : 1542,
-                    "var2" : 1642.0
-                },
-                {
-                    "base_var": 2142.0,
-                    "base2_var1": 2242.0,
-                    "base2_var2": 2342.0,
-                    "base2_var3": 2442.0,
-                    "var1" : 2542,
-                    "var2" : 2642.0
-                },
-                {
-                    "$type": "MultipleInheritence",
-                    "base_var": 3142.0,
-                    "base2_var1": 3242.0,
-                    "base2_var2": 3342.0,
-                    "base2_var3": 3442.0,
-                    "var1" : 3542,
-                    "var2" : 3642.0
-                },
-                {
-                    "base_var": 4142.0,
-                    "base2_var1": 4242.0,
-                    "base2_var2": 4342.0,
-                    "base2_var3": 4442.0,
-                    "var1" : 4542,
-                    "var2" : 4642.0
-                }
-            ])";
-        }
-
         void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
         {
             Base::Reflect(context);
             MultipleInheritence::Reflect(context, true);
         }
 
+        void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
+        {
+            Base::ConfigureFeatures(features);
+            // These tests don't work with pointers because there'll be a random value in the pointer
+            // which the Json Serialization will try to delete. The POD version of these tests already cover
+            // these cases.
+            features.m_enableNewInstanceTests = false;
+        }
+
         bool AreEqual(const Array& lhs, const Array& rhs) override
         {
             size_t size = lhs.size();
@@ -311,6 +277,11 @@ namespace JsonSerializationTests
                     return rhs[i] == nullptr;
                 }
 
+                if (rhs[i] == nullptr)
+                {
+                    return false;
+                }
+
                 if (!static_cast<const MultipleInheritence*>(lhs[i])->Equals(*static_cast<const MultipleInheritence*>(rhs[i]), true))
                 {
                     return false;

+ 21 - 3
Code/Framework/AzCore/Tests/Serialization/Json/BasicContainerSerializerTests.cpp

@@ -54,6 +54,11 @@ namespace JsonSerializationTests
             return AZStd::make_shared<Container>(Container{ 188, 288, 388 });
         }
 
+        AZStd::shared_ptr<Container> CreateSingleArrayDefaultInstance() override
+        {
+            return AZStd::make_shared<Container>(Container{ 0 });
+        }
+
         AZStd::string_view GetJsonForFullySetInstance() override
         {
             return "[188, 288, 388]";
@@ -120,6 +125,13 @@ namespace JsonSerializationTests
                 &SimplePointerTestDescription::Delete);
         }
 
+        AZStd::shared_ptr<Container> CreateSingleArrayDefaultInstance() override
+        {
+            int* value = reinterpret_cast<int*>(azmalloc(sizeof(int), alignof(int)));
+            *value = 0;
+            return AZStd::shared_ptr<Container>(new Container{ value }, &SimplePointerTestDescription::Delete);
+        }
+
         AZStd::string_view GetJsonForFullySetInstance() override
         {
             return "[188, 288, 388]";
@@ -180,6 +192,13 @@ namespace JsonSerializationTests
             return instance;
         }
 
+        AZStd::shared_ptr<Container> CreateSingleArrayDefaultInstance() override
+        {
+            auto instance = AZStd::make_shared<Container>();
+            *instance = { SimpleClass{} };
+            return instance;
+        }
+
         AZStd::string_view GetJsonForFullySetInstance() override
         {
             return R"([
@@ -301,7 +320,7 @@ namespace JsonSerializationTests
         
         ResultCode result = m_serializer->Store(*m_jsonDocument, &instance, &instance, azrtti_typeid(&instance), *m_jsonSerializationContext);
         EXPECT_EQ(Processing::Completed, result.GetProcessing());
-        EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
         Expect_DocStrEq("[{}]");
     }
 
@@ -315,7 +334,7 @@ namespace JsonSerializationTests
 
         ResultCode result = m_serializer->Store(*m_jsonDocument, &instance, nullptr, azrtti_typeid(&instance), *m_jsonSerializationContext);
         EXPECT_EQ(Processing::Completed, result.GetProcessing());
-        EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
         Expect_DocStrEq("[{},{}]");
     }
 
@@ -330,7 +349,6 @@ namespace JsonSerializationTests
         ResultCode result = m_serializer->Store(*m_jsonDocument, &instance, nullptr, azrtti_typeid(&instance), *m_jsonSerializationContext);
         EXPECT_EQ(Processing::Completed, result.GetProcessing());
         EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
-        EXPECT_NE(Outcomes::DefaultsUsed, result.GetOutcome());
         Expect_DocStrEq(R"([{"$type": "SimpleInheritence"},{"$type": "SimpleInheritence"}])");
     }
 

+ 18 - 0
Code/Framework/AzCore/Tests/Serialization/Json/BoolSerializerTests.cpp

@@ -63,6 +63,18 @@ namespace JsonSerializationTests
         : public BaseJsonSerializerFixture
     {
     public:
+        struct BoolPointerWrapper
+        {
+            AZ_TYPE_INFO(BoolPointerWrapper, "{2E67C069-BB0F-4F00-A704-E964F5FE5ED2}");
+
+            bool* m_value{ nullptr };
+
+            ~BoolPointerWrapper()
+            {
+                azfree(m_value);
+            }
+        };
+
         void SetUp() override
         {
             BaseJsonSerializerFixture::SetUp();
@@ -75,6 +87,12 @@ namespace JsonSerializationTests
             BaseJsonSerializerFixture::TearDown();
         }
 
+        void RegisterAdditional(AZStd::unique_ptr<AZ::SerializeContext>& serializeContext) override
+        {
+            serializeContext->Class<BoolPointerWrapper>()
+                ->Field("Value", &BoolPointerWrapper::m_value);
+        }
+
         void Load(rapidjson::Value& testVal, bool expectedBool, AZ::JsonSerializationResult::Outcomes expectedOutcome)
         {
             using namespace AZ::JsonSerializationResult;

+ 22 - 1
Code/Framework/AzCore/Tests/Serialization/Json/DoubleSerializerTests.cpp

@@ -32,7 +32,7 @@ namespace JsonSerializationTests
 
         AZStd::shared_ptr<FloatingPointType> CreateDefaultInstance() override
         {
-            return AZStd::make_shared<FloatingPointType>(-2.0f);
+            return AZStd::make_shared<FloatingPointType>(0.0f);
         }
 
         AZStd::shared_ptr<FloatingPointType> CreateFullySetInstance() override
@@ -71,6 +71,20 @@ namespace JsonSerializationTests
         : public BaseJsonSerializerFixture
     {
     public:
+        struct DoublePointerWrapper
+        {
+            AZ_TYPE_INFO(DoublePointerWrapper, "{C2FD9E0B-2641-4D24-A3D9-A29FD1A21A81}");
+
+            double* m_double{ nullptr };
+            float* m_float{ nullptr };
+
+            ~DoublePointerWrapper()
+            {
+                azfree(m_float);
+                azfree(m_double);
+            }
+        };
+
         void SetUp() override
         {
             BaseJsonSerializerFixture::SetUp();
@@ -85,6 +99,13 @@ namespace JsonSerializationTests
             BaseJsonSerializerFixture::TearDown();
         }
 
+        void RegisterAdditional(AZStd::unique_ptr<AZ::SerializeContext>& serializeContext) override
+        {
+            serializeContext->Class<DoublePointerWrapper>()
+                ->Field("Double", &DoublePointerWrapper::m_double)
+                ->Field("Float", &DoublePointerWrapper::m_float);
+        }
+
         void TestSerializers(rapidjson::Value& testVal, double expectedValue, AZ::JsonSerializationResult::Outcomes expectedOutcome)
         {
             using namespace AZ::JsonSerializationResult;

+ 213 - 4
Code/Framework/AzCore/Tests/Serialization/Json/JsonSerializerConformityTests.h

@@ -62,6 +62,14 @@ namespace JsonSerializationTests
         //! can be used to manually create these documents. If that is also not an option the tests can be
         //! disabled by setting this flag to false.
         bool m_supportsInjection{ true };
+        //! Enables the check that tries to determine if variables are initialized and if not whether they have the
+        //! OperationFlags::ManualDefault set. This applies for instance to integers, which won't be initialized if
+        //! constructed a new instance is created for pointers.
+        bool m_enableInitializationTest{ true };
+        //! Enable the test that creates a new instance of the provided test type through the factory that's found in
+        //! the Serialize Context. This test is automatically disabled for classes that don't have a factory or
+        //! have a null factory as well as for classes that have mandatory fields.
+        bool m_enableNewInstanceTests{ true };
 
     private:
         // There's no way to retrieve the number of types from RapidJSON so they're hard-coded here.
@@ -87,6 +95,7 @@ namespace JsonSerializationTests
     {
     public:
         using Type = T;
+
         virtual ~JsonSerializerConformityTestDescriptor() = default;
 
         virtual AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() = 0;
@@ -104,13 +113,21 @@ namespace JsonSerializationTests
         virtual AZStd::shared_ptr<T> CreatePartialDefaultInstance() { return nullptr; }
         //! Create an instance where all values are set to non-default values.
         virtual AZStd::shared_ptr<T> CreateFullySetInstance() = 0;
+        //! Create an instance of the target array type with a single value that has all defaults.
+        //! If the target type doesn't support arrays or requires more than one entry this can be ignored and
+        //! tests using this value will be skipped.
+        virtual AZStd::shared_ptr<T> CreateSingleArrayDefaultInstance() { return nullptr; }
 
         //! Get the json that represents the default instance.
         //! If the target type doesn't support partial specialization this can be ignored and
         //! tests for partial support will be skipped.
-        virtual AZStd::string_view GetJsonForPartialDefaultInstance() { return "";  }
+        virtual AZStd::string_view GetJsonForPartialDefaultInstance() { return ""; }
         //! Get the json that represents the instance with all values set.
         virtual AZStd::string_view GetJsonForFullySetInstance() = 0;
+        //! Get the json that represents an array with a single value that has only defaults.
+        //! If the target type doesn't support arrays or requires more than one entry this can be ignored and
+        //! tests using this value will be skipped.
+        virtual AZStd::string_view GetJsonForSingleArrayDefaultInstance() { return "[{}]"; }
         //! Get the json where additional values are added to the json file.
         //! If this function is not overloaded, but features.m_supportsInjection is enabled then
         //! the Json Serializer Conformity Tests will inject extra values in the json for a fully.
@@ -138,12 +155,15 @@ namespace JsonSerializationTests
         virtual AZStd::string_view GetJsonFor_Load_DeserializeUnreflectedType() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Load_DeserializeFullySetInstance() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Load_DeserializePartialInstance() { return this->GetJsonForPartialDefaultInstance(); }
+        virtual AZStd::string_view GetJsonFor_Load_DeserializeArrayWithDefaultValue() { return this->GetJsonForSingleArrayDefaultInstance(); }
+        virtual AZStd::string_view GetJsonFor_Load_DeserializeFullInstanceOnTopOfPartialDefaulted() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Load_HaltedThroughCallback() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Store_SerializeWithDefaultsKept() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Store_SerializeFullySetInstance() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Store_SerializeWithoutDefault() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Store_SerializeWithoutDefaultAndDefaultsKept() { return this->GetJsonForFullySetInstance(); }
         virtual AZStd::string_view GetJsonFor_Store_SerializePartialInstance() { return this->GetJsonForPartialDefaultInstance(); }
+        virtual AZStd::string_view GetJsonFor_Store_SerializeArrayWithSingleDefaultValue() { return this->GetJsonForSingleArrayDefaultInstance(); }
     };
 
     template<typename T>
@@ -154,6 +174,21 @@ namespace JsonSerializationTests
         using Description = T;
         using Type = typename T::Type;
 
+        struct PointerWrapper
+        {
+            AZ_TYPE_INFO(PointerWrapper, "{32FA6645-074A-458A-B79C-B173D0BD4B42}");
+            AZ_CLASS_ALLOCATOR(PointerWrapper, AZ::SystemAllocator, 0);
+
+            Type* m_value{ nullptr };
+
+            ~PointerWrapper()
+            {
+                // Using free because not all types can safely use delete. Since this just to clear the memory to satisfy the memory
+                // leak test, this is fine.
+                azfree(m_value);
+            }
+        };
+
         void SetUp() override
         {
             using namespace AZ::JsonSerializationResult;
@@ -165,6 +200,7 @@ namespace JsonSerializationTests
             descriptor->ConfigureFeatures(this->m_features);
             descriptor->Reflect(this->m_serializeContext);
             descriptor->Reflect(this->m_jsonRegistrationContext);
+            this->m_serializeContext->template Class<PointerWrapper>()->Field("Value", &PointerWrapper::m_value);
             
             this->m_deserializationSettings->m_reporting = &Internal::VerifyCallback;
             this->m_serializationSettings->m_reporting = &Internal::VerifyCallback;
@@ -185,6 +221,7 @@ namespace JsonSerializationTests
             this->m_jsonRegistrationContext->DisableRemoveReflection();
 
             this->m_serializeContext->EnableRemoveReflection();
+            this->m_serializeContext->template Class<PointerWrapper>()->Field("Value", &PointerWrapper::m_value);
             descriptor->Reflect(this->m_serializeContext);
             this->m_serializeContext->DisableRemoveReflection();
 
@@ -487,6 +524,41 @@ namespace JsonSerializationTests
         }
     }
 
+    TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeArrayWithDefaultValue_SucceedsAndReportPartialDefaults)
+    {
+        using namespace AZ::JsonSerializationResult;
+
+        if (this->m_features.SupportsJsonType(rapidjson::kArrayType))
+        {
+            this->m_jsonDocument->Parse(this->m_description.GetJsonFor_Load_DeserializeArrayWithDefaultValue().data());
+            ASSERT_FALSE(this->m_jsonDocument->HasParseError());
+
+            auto serializer = this->m_description.CreateSerializer();
+            auto instance = this->m_description.CreateDefaultInstance();
+            
+            this->m_jsonDeserializationContext->PushPath(DefaultPath);
+
+            ResultCode result =
+                serializer->Load(instance.get(), azrtti_typeid(*instance), *this->m_jsonDocument, *this->m_jsonDeserializationContext);
+
+            if (this->m_features.m_fixedSizeArray)
+            {
+                EXPECT_EQ(Outcomes::Unsupported, result.GetOutcome());
+                EXPECT_EQ(Processing::Altered, result.GetProcessing());
+            }
+            else
+            {
+                EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
+                EXPECT_EQ(Processing::Completed, result.GetProcessing());
+
+                auto compare = this->m_description.CreateSingleArrayDefaultInstance();
+                ASSERT_NE(nullptr, compare)
+                    << "Conformity tests for variably sized arrays require an implementation of CreateSingleArrayDefaultInstance";
+                EXPECT_TRUE(this->m_description.AreEqual(*compare, *instance));
+            }
+        }
+    }
+
     TYPED_TEST_P(JsonSerializerConformityTests, Load_InterruptClearingTarget_ContainerIsNotCleared)
     {
         using namespace AZ::JsonSerializationResult;
@@ -548,7 +620,6 @@ namespace JsonSerializationTests
         this->m_jsonDocument->Parse(json.data());
         ASSERT_FALSE(this->m_jsonDocument->HasParseError());
 
-        auto serializer = this->m_description.CreateSerializer();
         auto instance = this->m_description.CreateDefaultConstructedInstance();
         auto compare = this->m_description.CreateFullySetInstance();
 
@@ -622,6 +693,94 @@ namespace JsonSerializationTests
         }
     }
 
+    TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeFullInstanceOnTopOfPartialDefaulted_SucceedsAndObjectMatchesParialInstance)
+    {
+        using namespace AZ::JsonSerializationResult;
+
+        if (this->m_features.m_supportsPartialInitialization)
+        {
+            AZStd::string_view json = this->m_description.GetJsonFor_Load_DeserializeFullInstanceOnTopOfPartialDefaulted();
+            // If tests for partial initialization are enabled than json for the partial initialization is needed.
+            ASSERT_FALSE(json.empty());
+            this->m_jsonDocument->Parse(json.data());
+            ASSERT_FALSE(this->m_jsonDocument->HasParseError());
+
+            auto serializer = this->m_description.CreateSerializer();
+            auto instance = this->m_description.CreatePartialDefaultInstance();
+            auto compare = this->m_description.CreateFullySetInstance();
+            ASSERT_NE(nullptr, compare);
+
+            // Clear containers which should effectively turn them into default containers.
+            this->m_deserializationSettings->m_clearContainers = true;
+            this->ResetJsonContexts();
+            this->m_jsonDeserializationContext->PushPath(DefaultPath);
+
+            ResultCode result =
+                serializer->Load(instance.get(), azrtti_typeid(*instance), *this->m_jsonDocument, *this->m_jsonDeserializationContext);
+
+            EXPECT_EQ(Outcomes::Success, result.GetOutcome());
+            EXPECT_EQ(Processing::Completed, result.GetProcessing());
+            EXPECT_TRUE(this->m_description.AreEqual(*instance, *compare));
+        }
+    }
+
+    TYPED_TEST_P(JsonSerializerConformityTests, Load_DefaultToPointer_SucceedsAndValueIsInitialized)
+    {
+        using namespace AZ::JsonSerializationResult;
+
+        if (this->m_features.m_enableNewInstanceTests && this->m_features.m_mandatoryFields.empty())
+        {
+            AZ::SerializeContext* serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
+            const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(azrtti_typeid<typename TypeParam::Type>());
+            ASSERT_NE(nullptr, classData);
+            // Skip this test if the target type doesn't have a factor to create a new instance with or if the factor explicit
+            // prohibits construction.
+            if (classData->m_factory && classData->m_factory != AZ::Internal::NullFactory::GetInstance())
+            {
+                typename JsonSerializerConformityTests<TypeParam>::PointerWrapper instance;
+                auto compare = this->m_description.CreateDefaultInstance();
+
+                this->m_jsonDocument->Parse(R"({ "Value": {}})");
+                ASSERT_FALSE(this->m_jsonDocument->HasParseError());
+
+                AZ::JsonDeserializerSettings settings;
+                settings.m_serializeContext = serializeContext;
+                settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
+                ResultCode result = AZ::JsonSerialization::Load(instance, *this->m_jsonDocument, settings);
+
+                EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+                EXPECT_EQ(Processing::Completed, result.GetProcessing());
+                ASSERT_NE(nullptr, instance.m_value);
+                EXPECT_TRUE(this->m_description.AreEqual(*instance.m_value, *compare));
+            }
+        }
+    }
+
+    TYPED_TEST_P(JsonSerializerConformityTests, Load_InitializeNewInstance_SucceedsAndValueIsInitialized)
+    {
+        using namespace AZ;
+        using namespace AZ::JsonSerializationResult;
+
+        if (this->m_features.m_enableNewInstanceTests && this->m_features.m_mandatoryFields.empty())
+        {
+            auto serializer = this->m_description.CreateSerializer();
+            if ((serializer->GetOperationsFlags() & BaseJsonSerializer::OperationFlags::InitializeNewInstance) ==
+                BaseJsonSerializer::OperationFlags::InitializeNewInstance)
+            {
+                typename TypeParam::Type instance;
+                auto compare = this->m_description.CreateDefaultInstance();
+                this->m_jsonDocument->SetObject();
+
+                ResultCode result =
+                    serializer->Load(&instance, azrtti_typeid(instance), *this->m_jsonDocument, *this->m_jsonDeserializationContext);
+
+                EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+                EXPECT_EQ(Processing::Completed, result.GetProcessing());
+                EXPECT_TRUE(this->m_description.AreEqual(instance, *compare));
+            }
+        }
+    }
+
     TYPED_TEST_P(JsonSerializerConformityTests, Load_HaltedThroughCallback_LoadFailsAndHaltReported)
     {
         using namespace AZ::JsonSerializationResult;
@@ -909,6 +1068,28 @@ namespace JsonSerializationTests
         }
     }
 
+    TYPED_TEST_P(JsonSerializerConformityTests, Store_SerializeArrayWithSingleDefaultValue_StoredSuccessfullyAndJsonMatches)
+    {
+        using namespace AZ::JsonSerializationResult;
+
+        if (this->m_features.SupportsJsonType(rapidjson::kArrayType) && !this->m_features.m_fixedSizeArray)
+        {
+            this->m_jsonSerializationContext->PushPath(DefaultPath);
+
+            auto serializer = this->m_description.CreateSerializer();
+            auto instance = this->m_description.CreateSingleArrayDefaultInstance();
+            ASSERT_NE(nullptr, instance)
+                << "Conformity tests for variably sized arrays require an implementation of CreateSingleArrayDefaultInstance";
+
+            ResultCode result = serializer->Store(
+                *this->m_jsonDocument, instance.get(), instance.get(), azrtti_typeid(*instance), *this->m_jsonSerializationContext);
+
+            EXPECT_EQ(Processing::Completed, result.GetProcessing());
+            EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
+            this->Expect_DocStrEq(this->m_description.GetJsonFor_Store_SerializeArrayWithSingleDefaultValue());
+        }
+    }
+
     TYPED_TEST_P(JsonSerializerConformityTests, Store_HaltedThroughCallback_StoreFailsAndHaltReported)
     {
         using namespace AZ::JsonSerializationResult;
@@ -1017,7 +1198,29 @@ namespace JsonSerializationTests
         }
     }
 
-    TYPED_TEST_P(JsonSerializerConformityTests, GetOperationsFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared)
+    TYPED_TEST_P(JsonSerializerConformityTests, GetOperationFlags_RequiresExplicitInit_ObjectsThatDoNotConstructHaveExplicitInitOption)
+    {
+        using namespace AZ;
+        using namespace AZ::JsonSerializationResult;
+
+        if (this->m_features.m_enableInitializationTest)
+        {
+            auto instance = this->m_description.CreateDefaultInstance();
+            typename TypeParam::Type compare;
+            if (!this->m_description.AreEqual(*instance, compare))
+            {
+                auto serializer = this->m_description.CreateSerializer();
+                BaseJsonSerializer::OperationFlags flags = serializer->GetOperationsFlags();
+                bool hasManualDefaultSet =
+                    (flags & BaseJsonSerializer::OperationFlags::ManualDefault) == BaseJsonSerializer::OperationFlags::ManualDefault ||
+                    (flags & BaseJsonSerializer::OperationFlags::InitializeNewInstance) ==
+                        BaseJsonSerializer::OperationFlags::InitializeNewInstance;   
+                EXPECT_TRUE(hasManualDefaultSet);
+            }
+        }
+    }
+
+    TYPED_TEST_P(JsonSerializerConformityTests, GetOperationFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared)
     {
         if (this->m_features.SupportsJsonType(rapidjson::kObjectType))
         {
@@ -1048,10 +1251,14 @@ namespace JsonSerializationTests
         Load_DeserializeEmptyArray_SucceedsAndObjectMatchesDefaults,
         Load_DeserializeEmptyArrayWithClearEnabled_SucceedsAndObjectMatchesDefaults,
         Load_DeserializeEmptyArrayWithClearedTarget_SucceedsAndObjectMatchesDefaults,
+        Load_DeserializeArrayWithDefaultValue_SucceedsAndReportPartialDefaults,
         Load_InterruptClearingTarget_ContainerIsNotCleared,
         Load_DeserializeFullySetInstance_SucceedsAndObjectMatchesFullySetInstance,
         Load_DeserializeFullySetInstanceThroughMainLoad_SucceedsAndObjectMatchesFullySetInstance,
         Load_DeserializePartialInstance_SucceedsAndObjectMatchesParialInstance,
+        Load_DeserializeFullInstanceOnTopOfPartialDefaulted_SucceedsAndObjectMatchesParialInstance,
+        Load_DefaultToPointer_SucceedsAndValueIsInitialized,
+        Load_InitializeNewInstance_SucceedsAndValueIsInitialized,
         Load_DeserializeWithMissingMandatoryField_LoadFailedAndUnsupportedReported,
         Load_InsertAdditionalData_SucceedsAndObjectMatchesFullySetInstance,
         Load_HaltedThroughCallback_LoadFailsAndHaltReported,
@@ -1066,13 +1273,15 @@ namespace JsonSerializationTests
         Store_SerializeWithoutDefaultAndDefaultsKept_StoredSuccessfullyAndJsonMatches,
         Store_SerializePartialInstance_StoredSuccessfullyAndJsonMatches,
         Store_SerializeEmptyArray_StoredSuccessfullyAndJsonMatches,
+        Store_SerializeArrayWithSingleDefaultValue_StoredSuccessfullyAndJsonMatches,
         Store_HaltedThroughCallback_StoreFailsAndHaltReported,
 
         StoreLoad_RoundTripWithPartialDefault_IdenticalInstances,
         StoreLoad_RoundTripWithFullSet_IdenticalInstances,
         StoreLoad_RoundTripWithDefaultsKept_IdenticalInstances,
 
-        GetOperationsFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared);
+        GetOperationFlags_RequiresExplicitInit_ObjectsThatDoNotConstructHaveExplicitInitOption,
+        GetOperationFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared);
 } // namespace JsonSerializationTests
 
 namespace AZ

+ 115 - 13
Code/Framework/AzCore/Tests/Serialization/Json/MapSerializerTests.cpp

@@ -35,6 +35,11 @@ namespace JsonSerializationTests
             return AZStd::make_shared<Map>();
         }
 
+        AZStd::string_view GetJsonForSingleArrayDefaultInstance() override
+        {
+            return R"({ "{}": {} })";
+        }
+
         void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
         {
             features.EnableJsonType(rapidjson::kArrayType);
@@ -61,6 +66,13 @@ namespace JsonSerializationTests
     public:
         using Map = T<int, double>;
 
+        AZStd::shared_ptr<Map> CreateSingleArrayDefaultInstance() override
+        {
+            auto instance = AZStd::make_shared<Map>();
+            instance->emplace(AZStd::make_pair(0, 0.0));
+            return instance;
+        }
+
         AZStd::shared_ptr<Map> CreateFullySetInstance() override
         {
             auto instance = AZStd::make_shared<Map>();
@@ -100,6 +112,13 @@ namespace JsonSerializationTests
     public:
         using Map = T<AZStd::string, double>;
 
+        AZStd::shared_ptr<Map> CreateSingleArrayDefaultInstance() override
+        {
+            auto instance = AZStd::make_shared<Map>();
+            instance->emplace(AZStd::make_pair(AZStd::string(), 0.0));
+            return instance;
+        }
+
         AZStd::shared_ptr<Map> CreateFullySetInstance() override
         {
             auto instance = AZStd::make_shared<Map>();
@@ -163,6 +182,14 @@ namespace JsonSerializationTests
             return instance;
         }
 
+        AZStd::shared_ptr<Map> CreateSingleArrayDefaultInstance() override
+        {
+            auto instance = AZStd::shared_ptr<Map>(new Map{}, &Delete);
+            instance->emplace(AZStd::make_pair(aznew SimpleClass(), aznew SimpleClass()));
+            return instance;
+        }
+
+
         AZStd::string_view GetJsonForPartialDefaultInstance() override
         {
             if constexpr (IsMultiMap)
@@ -237,13 +264,23 @@ namespace JsonSerializationTests
                 return false;
             }
 
-            auto compare = [](typename Map::const_reference lhs, typename Map::const_reference rhs) -> bool
+            // Naive compare to avoid having to split up the test because comparing for ordered and unordered maps would need to be
+            // different.
+            for (auto&& [key, value] : lhs)
             {
-                return
-                    lhs.first->Equals(*rhs.first, true) &&
-                    lhs.second->Equals(*rhs.second, true);
-            };
-            return AZStd::equal(lhs.begin(), lhs.end(), rhs.begin(), compare);
+                for (auto&& [keyCompare, valueCompare] : rhs)
+                {
+                    if (key->Equals(*keyCompare, true))
+                    {
+                        if (!value->Equals(*valueCompare, true))
+                        {
+                            return false;
+                        }
+                        break;
+                    }
+                }
+            }
+            return true;
         }
     };
 
@@ -393,6 +430,29 @@ namespace JsonSerializationTests
     {
         using namespace AZ::JsonSerializationResult;
 
+        m_jsonDocument->Parse(R"(
+        {
+            "{}": {}
+        })");
+        ASSERT_FALSE(m_jsonDocument->HasParseError());
+
+        TestStringMap values;
+        ResultCode result = m_unorderedMapSerializer.Load(&values, azrtti_typeid(&values), *m_jsonDocument, *m_jsonDeserializationContext);
+
+        EXPECT_EQ(Processing::Completed, result.GetProcessing());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
+
+        EXPECT_EQ(1, values.size());
+
+        auto defaultKey = values.find(TestString());
+        EXPECT_NE(values.end(), defaultKey);
+        EXPECT_STRCASEEQ(TestString().m_value.c_str(), defaultKey->second.m_value.c_str());
+    }
+
+    TEST_F(JsonMapSerializerTests, Load_DefaultForStringKeyAndAdditionalValue_LoadedBackWithDefaults)
+    {
+        using namespace AZ::JsonSerializationResult;
+
         m_jsonDocument->Parse(R"(
             {
                 "{}": {},
@@ -563,13 +623,13 @@ namespace JsonSerializationTests
         EXPECT_EQ(Outcomes::Catastrophic, result.GetOutcome());
     }
 
-    TEST_F(JsonMapSerializerTests, Load_DefaultValueInMultiMap_DefaultUsed)
+    TEST_F(JsonMapSerializerTests, Load_DefaultObjectInMultiMap_DefaultUsed)
     {
         using namespace AZ::JsonSerializationResult;
 
         m_jsonDocument->Parse(R"(
             {
-                "Hello": {}
+                "World": {}
             })");
         ASSERT_FALSE(m_jsonDocument->HasParseError());
 
@@ -580,18 +640,41 @@ namespace JsonSerializationTests
         EXPECT_EQ(Processing::Completed, result.GetProcessing());
         EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
 
+        ASSERT_FALSE(values.empty());
+        EXPECT_STREQ("World", values.begin()->first.m_value.c_str());
+        EXPECT_STREQ(TestString().m_value.c_str(), values.begin()->second.m_value.c_str());
+    }
+
+    TEST_F(JsonMapSerializerTests, Load_FullDefaultObjectInMultiMap_DefaultUsed)
+    {
+        using namespace AZ::JsonSerializationResult;
+
+        m_jsonDocument->Parse(R"(
+            {
+                "{}": {}
+            })");
+        ASSERT_FALSE(m_jsonDocument->HasParseError());
+
+        TestStringMultiMap values;
+        ResultCode result =
+            m_unorderedMultiMapSerializer.Load(&values, azrtti_typeid(&values), *m_jsonDocument, *m_jsonDeserializationContext);
+
+        EXPECT_EQ(Processing::Completed, result.GetProcessing());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
+
         ASSERT_FALSE(values.empty());
         EXPECT_STREQ("Hello", values.begin()->first.m_value.c_str());
+        EXPECT_STREQ("Hello", values.begin()->second.m_value.c_str());
         EXPECT_STREQ(TestString().m_value.c_str(), values.begin()->second.m_value.c_str());
     }
 
-    TEST_F(JsonMapSerializerTests, Load_DefaultArrayValueInMultiMap_DefaultUsed)
+    TEST_F(JsonMapSerializerTests, Load_DefaultObjectValueInMultiMap_DefaultUsed)
     {
         using namespace AZ::JsonSerializationResult;
 
         m_jsonDocument->Parse(R"(
             {
-                "Hello": [{}]
+                "World": [{}]
             })");
         ASSERT_FALSE(m_jsonDocument->HasParseError());
 
@@ -603,7 +686,8 @@ namespace JsonSerializationTests
         EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
 
         ASSERT_FALSE(values.empty());
-        EXPECT_STREQ("Hello", values.begin()->first.m_value.c_str());
+        EXPECT_STREQ("World", values.begin()->first.m_value.c_str());
+        EXPECT_STREQ("Hello", values.begin()->second.m_value.c_str());
         EXPECT_STREQ(TestString().m_value.c_str(), values.begin()->second.m_value.c_str());
     }
 
@@ -636,7 +720,7 @@ namespace JsonSerializationTests
             azrtti_typeid(&values), *m_jsonSerializationContext);
 
         EXPECT_EQ(Processing::Completed, result.GetProcessing());
-        EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
         Expect_DocStrEq(R"(
             {
                 "{}": {}
@@ -654,7 +738,25 @@ namespace JsonSerializationTests
             azrtti_typeid(&values), *m_jsonSerializationContext);
 
         EXPECT_EQ(Processing::Completed, result.GetProcessing());
-        EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
+        Expect_DocStrEq(R"(
+            {
+                "{}": {}
+            })");
+    }
+
+    TEST_F(JsonMapSerializerTests, Store_SingleAllDefaulValue_InitializedWithDefaults)
+    {
+        using namespace AZ::JsonSerializationResult;
+
+        SimpleClassMap values;
+        values.emplace(SimpleClass(), SimpleClass());
+        
+        ResultCode result =
+            m_unorderedMapSerializer.Store(*m_jsonDocument, &values, nullptr, azrtti_typeid(&values), *m_jsonSerializationContext);
+
+        EXPECT_EQ(Processing::Completed, result.GetProcessing());
+        EXPECT_EQ(Outcomes::PartialDefaults, result.GetOutcome());
         Expect_DocStrEq(R"(
             {
                 "{}": {}

+ 44 - 0
Code/Framework/AzCore/Tests/Serialization/Json/TestCases_Patching.cpp

@@ -303,6 +303,29 @@ namespace JsonSerializationTests
             R"( { "foo": [ "bar", "baz" ] })");
     }
 
+    TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchRemoveArrayMembersInCorrectOrder_ReportsSuccess)
+    {
+        CheckApplyPatch(
+            R"( { "foo": [ "bar", "qux", "baz" ] })",
+            R"( [
+                    { "op": "remove", "path": "/foo/2" },
+                    { "op": "remove", "path": "/foo/1" }
+                ])",
+            R"( { "foo": [ "bar" ] })");
+    }
+
+    TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchRemoveArrayMembersInWrongOrder_ReportsError)
+    {
+        using namespace AZ::JsonSerializationResult;
+        CheckApplyPatchOutcome(
+            R"( { "foo": [ "bar", "qux", "baz" ] })",
+            R"( [
+                    { "op": "remove", "path": "/foo/1" },
+                    { "op": "remove", "path": "/foo/2" }
+                ])",
+            Outcomes::Invalid, Processing::Halted);
+    }
+
     TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchRemoveOperationInvalidParent_ReportError)
     {
         using namespace AZ::JsonSerializationResult;
@@ -949,6 +972,27 @@ namespace JsonSerializationTests
         );
     }
 
+    TEST_F(JsonPatchingSerializationTests, CreatePatch_UseJsonPatchRemoveLastArrayEntries_MultipleOperationsInCorrectOrder)
+    {
+        CheckCreatePatch(
+            R"( [ "foo", "hello", "bar" ])", R"( [ "foo" ])",
+            R"( [
+                    { "op": "remove", "path": "/2" },
+                    { "op": "remove", "path": "/1" }
+                ])");
+    }
+
+    TEST_F(JsonPatchingSerializationTests, CreatePatch_UseJsonPatchRemoveAllArrayEntries_MultipleOperationsInCorrectOrder)
+    {
+        CheckCreatePatch(
+            R"( [ "foo", "hello", "bar" ])", R"( [])",
+            R"( [
+                    { "op": "remove", "path": "/2" },
+                    { "op": "remove", "path": "/1" },
+                    { "op": "remove", "path": "/0" }
+                ])");
+    }
+
     TEST_F(JsonPatchingSerializationTests, CreatePatch_UseJsonPatchRemoveObjectFromArrayInMiddle_OperationToUpdateMember)
     {
         CheckCreatePatch(

+ 7 - 6
Code/Framework/AzCore/Tests/Serialization/Json/TupleSerializerTests.cpp

@@ -48,12 +48,12 @@ namespace JsonSerializationTests
 
         AZStd::shared_ptr<Pair> CreateDefaultInstance() override
         {
-            return AZStd::make_shared<Pair>(142, 242.0);
+            return AZStd::make_shared<Pair>(0, 0.0);
         }
 
         AZStd::shared_ptr<Pair> CreatePartialDefaultInstance() override
         {
-            return AZStd::make_shared<Pair>(142, 288.0);
+            return AZStd::make_shared<Pair>(0, 288.0);
         }
 
         AZStd::shared_ptr<Pair> CreateFullySetInstance() override
@@ -102,12 +102,12 @@ namespace JsonSerializationTests
 
         AZStd::shared_ptr<Tuple> CreateDefaultInstance() override
         {
-            return AZStd::make_shared<Tuple>(142, 242.0, 342.0f);
+            return AZStd::make_shared<Tuple>(0, 0.0, 0.0f);
         }
 
         AZStd::shared_ptr<Tuple> CreatePartialDefaultInstance() override
         {
-            return AZStd::make_shared<Tuple>(142, 288.0, 342.0f);
+            return AZStd::make_shared<Tuple>(0, 288.0, 0.0f);
         }
 
         AZStd::shared_ptr<Tuple> CreateFullySetInstance() override
@@ -345,6 +345,7 @@ namespace JsonSerializationTests
         {
             TupleSerializerTestsInternal::ConfigureFeatures(features);
             features.m_supportsPartialInitialization = true;
+            features.m_enableNewInstanceTests = false;
         }
 
         void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
@@ -447,14 +448,14 @@ namespace JsonSerializationTests
         {
             return AZStd::make_shared<Tuple>(
                 AZStd::vector<int>(), 
-                AZStd::make_pair(442, ""));
+                AZStd::make_pair(0, ""));
         }
 
         AZStd::shared_ptr<Tuple> CreatePartialDefaultInstance() override
         {
             return AZStd::make_shared<Tuple>(
                 AZStd::vector<int>(),
-                AZStd::make_pair(442, "hello"));
+                AZStd::make_pair(0, "hello"));
         }
 
         AZStd::shared_ptr<Tuple> CreateFullySetInstance() override

+ 10 - 0
Code/Framework/AzCore/Tests/Serialization/Json/UnorderedSetSerializerTests.cpp

@@ -36,6 +36,11 @@ namespace JsonSerializationTests
             return AZStd::make_shared<Set>();
         }
 
+        AZStd::shared_ptr<Set> CreateSingleArrayDefaultInstance() override
+        {
+            return AZStd::make_shared<Set>(Set{ 0 });
+        }
+
         AZStd::shared_ptr<Set> CreateFullySetInstance() override
         {
             return AZStd::make_shared<Set>(Set{42, -88, 342});
@@ -80,6 +85,11 @@ namespace JsonSerializationTests
             return AZStd::make_shared<MultiSet>();
         }
 
+        AZStd::shared_ptr<MultiSet> CreateSingleArrayDefaultInstance() override
+        {
+            return AZStd::make_shared<MultiSet>(MultiSet{ 0 });
+        }
+
         AZStd::shared_ptr<MultiSet> CreateFullySetInstance() override
         {
             return AZStd::make_shared<MultiSet>(MultiSet{ 42, -88, 42, 342 });

+ 2 - 1
Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsEvents.h

@@ -48,7 +48,8 @@ namespace AzPhysics
         using OnPresimulateEvent = AZ::Event<float>;
 
         //! Event triggers at the end of the SystemInterface::Simulate call.
-        using OnPostsimulateEvent = AZ::Event<>;
+        //! Parameter is the total time that the physics system will run for during the Simulate call.
+        using OnPostsimulateEvent = AZ::Event<float>;
 
         //! Event trigger when a Scene is added to the simulation.
         //! When triggered will send the handle to the new Scene.

+ 1 - 1
Code/Framework/AzFramework/AzFramework/Physics/Material.cpp

@@ -402,7 +402,7 @@ namespace Physics
                         ->Attribute(AZ_CRC_CE("EditButton"), "")
                         ->Attribute(AZ_CRC_CE("EditDescription"), "Open in Asset Editor")
                         ->Attribute(AZ::Edit::Attributes::DefaultAsset, &MaterialSelection::GetMaterialLibraryId)
-                    ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialIdsAssignedToSlots, "", "")
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &MaterialSelection::m_materialIdsAssignedToSlots, "Slots", "")
                         ->ElementAttribute(Attributes::MaterialLibraryAssetId, &MaterialSelection::GetMaterialLibraryId)
                         ->Attribute(AZ::Edit::Attributes::IndexedChildNameLabelOverride, &MaterialSelection::GetMaterialSlotLabel)
                         ->Attribute(AZ::Edit::Attributes::AutoExpand, true)

+ 1 - 1
Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp

@@ -43,7 +43,7 @@ namespace AzPhysics
             const AZ::BehaviorAzEventDescription postsimulateEventDescription =
             {
                 "Postsimulate event",
-                {} // Parameters
+                {"Tick time"} // Parameters
             };
 
             behaviorContext->Class<SystemInterface>("System Interface")

+ 22 - 33
Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityTransformBus.h

@@ -1,47 +1,36 @@
 /*
-* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
-* its licensors.
-*
-* For complete copyright and license terms please see the LICENSE at the root of this
-* distribution (the "License"). All use of this software is governed by the License,
-* or, if provided, by the license below or the license accompanying this file. Do not
-* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-*
-*/
-#include <AzCore/EBus/EBus.h>
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
 
 #pragma once
 
+#include <AzCore/EBus/EBus.h>
+
 namespace AzToolsFramework
 {
     using EntityIdList = AZStd::vector<AZ::EntityId>;
 
-    /*!
-     * Bus for notifications about entity transform changes from the editor viewport
-     */
-    class EditorTransformChangeNotifications
-        : public AZ::EBusTraits
+    //! Notifications about entity transform changes from the editor.
+    class EditorTransformChangeNotifications : public AZ::EBusTraits
     {
     public:
-        virtual ~EditorTransformChangeNotifications() = default;
-
-        /*!
-         * Notification that the specified entities are about to have their transforms changed due to user interaction in the editor viewport
-         *
-         * \param entityIds Entities about to be changed
-         */
-        virtual void OnEntityTransformChanging(const AzToolsFramework::EntityIdList& /*entityIds*/) {};
-
-        /*!
-         * Notification that the specified entities had their transforms changed due to user interaction in the editor viewport
-         *
-         * \param entityIds Entities changed
-         */
-        virtual void OnEntityTransformChanged(const AzToolsFramework::EntityIdList& /*entityIds*/) {};
+        //! A notification that these entities had their transforms changed due to a user interaction in the editor.
+        //! @param entityIds Entities that had their transform changed.
+        virtual void OnEntityTransformChanged([[maybe_unused]] const AzToolsFramework::EntityIdList& entityIds)
+        {
+        }
+
+    protected:
+        ~EditorTransformChangeNotifications() = default;
     };
 
     using EditorTransformChangeNotificationBus = AZ::EBus<EditorTransformChangeNotifications>;
-
 } // namespace AzToolsFramework
-

+ 23 - 9
Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.cpp

@@ -27,6 +27,7 @@
 #include <AzFramework/Components/TransformComponent.h>
 #include <AzFramework/Visibility/EntityBoundsUnionBus.h>
 #include <AzToolsFramework/API/EntityCompositionRequestBus.h>
+#include <AzToolsFramework/Entity/EditorEntityTransformBus.h>
 #include <AzToolsFramework/API/EntityPropertyEditorRequestsBus.h>
 #include <AzToolsFramework/API/ToolsApplicationAPI.h>
 #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
@@ -944,7 +945,7 @@ namespace AzToolsFramework
             return AZ::Success();
         }
 
-        AZ::u32 TransformComponent::ParentChanged()
+        AZ::u32 TransformComponent::ParentChangedInspector()
         {
             AZ::u32 refreshLevel = AZ::Edit::PropertyRefreshLevels::None;
 
@@ -974,12 +975,23 @@ namespace AzToolsFramework
             return refreshLevel;
         }
 
-        AZ::u32 TransformComponent::TransformChanged()
+        AZ::u32 TransformComponent::TransformChangedInspector()
+        {
+            if (TransformChanged())
+            {
+                AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
+                    &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
+                    EntityIdList{ GetEntityId() });
+            }
+
+            return AZ::Edit::PropertyRefreshLevels::None;
+        }
+
+        bool TransformComponent::TransformChanged()
         {
             if (!m_suppressTransformChangedEvent)
             {
-                auto parent = GetParentTransformComponent();
-                if (parent)
+                if (auto parent = GetParentTransformComponent())
                 {
                     OnTransformChanged(parent->GetLocalTM(), parent->GetWorldTM());
                 }
@@ -987,13 +999,15 @@ namespace AzToolsFramework
                 {
                     OnTransformChanged(AZ::Transform::Identity(), AZ::Transform::Identity());
                 }
+
+                return true;
             }
 
-            return AZ::Edit::PropertyRefreshLevels::None;
+            return false;
         }
 
         // This is called when our transform changes static state.
-        AZ::u32 TransformComponent::StaticChanged()
+        AZ::u32 TransformComponent::StaticChangedInspector()
         {
             AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
                 &AzToolsFramework::ToolsApplicationEvents::Bus::Events::InvalidatePropertyDisplay,
@@ -1175,10 +1189,10 @@ namespace AzToolsFramework
                             Attribute(AZ::Edit::Attributes::AutoExpand, true)->
                         DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_parentEntityId, "Parent entity", "")->
                             Attribute(AZ::Edit::Attributes::ChangeValidate, &TransformComponent::ValidatePotentialParent)->
-                            Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::ParentChanged)->
+                            Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::ParentChangedInspector)->
                             Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::DontGatherReference | AZ::Edit::SliceFlags::NotPushableOnSliceRoot)->
                         DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_editorTransform, "Values", "")->
-                            Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChanged)->
+                            Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::TransformChangedInspector)->
                             Attribute(AZ::Edit::Attributes::AutoExpand, true)->
                         DataElement(AZ::Edit::UIHandlers::Button, &TransformComponent::m_addNonUniformScaleButton, "", "")->
                             Attribute(AZ::Edit::Attributes::ButtonText, "Add non-uniform scale")->
@@ -1189,7 +1203,7 @@ namespace AzToolsFramework
                             EnumAttribute(AZ::TransformConfig::ParentActivationTransformMode::MaintainOriginalRelativeTransform, "Original relative transform")->
                             EnumAttribute(AZ::TransformConfig::ParentActivationTransformMode::MaintainCurrentWorldTransform, "Current world transform")->
                         DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_isStatic ,"Static", "Static entities are highly optimized and cannot be moved during runtime.")->
-                            Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::StaticChanged)->
+                            Attribute(AZ::Edit::Attributes::ChangeNotify, &TransformComponent::StaticChangedInspector)->
                         DataElement(AZ::Edit::UIHandlers::Default, &TransformComponent::m_cachedWorldTransformParent, "Cached Parent Entity", "")->
                             Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::DontGatherReference | AZ::Edit::SliceFlags::NotPushable)->
                             Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)->

+ 6 - 3
Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/TransformComponent.h

@@ -182,9 +182,12 @@ namespace AzToolsFramework
             static void Reflect(AZ::ReflectContext* context);
 
             AZ::Outcome<void, AZStd::string> ValidatePotentialParent(void* newValue, const AZ::Uuid& valueType);
-            AZ::u32 ParentChanged();
-            AZ::u32 TransformChanged();
-            AZ::u32 StaticChanged();
+
+            AZ::u32 TransformChangedInspector();
+            AZ::u32 ParentChangedInspector();
+            AZ::u32 StaticChangedInspector();
+
+            bool TransformChanged();
 
             AZ::Transform GetLocalTranslationTM() const;
             AZ::Transform GetLocalRotationTM() const;

+ 3 - 1
Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.cpp

@@ -165,11 +165,13 @@ namespace UnitTest
     void EditorEntityComponentChangeDetector::OnEntityTransformChanged(
         const AzToolsFramework::EntityIdList& entityIds)
     {
+        m_entityIds = entityIds;
+
         for (const AZ::EntityId& entityId : entityIds)
         {
             if (const auto* entity = GetEntityById(entityId))
             {
-                if (AZ::Component * transformComponent = entity->FindComponent<Components::TransformComponent>())
+                if (AZ::Component* transformComponent = entity->FindComponent<Components::TransformComponent>())
                 {
                     OnEntityComponentPropertyChanged(transformComponent->GetId());
                 }

+ 1 - 0
Code/Framework/AzToolsFramework/AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h

@@ -239,6 +239,7 @@ namespace UnitTest
         bool PropertyDisplayInvalidated() const { return m_propertyDisplayInvalidated; }
 
         AZStd::vector<AZ::ComponentId> m_componentIds;
+        AzToolsFramework::EntityIdList m_entityIds;
 
     private:
         // PropertyEditorEntityChangeNotificationBus ...

+ 31 - 12
Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp

@@ -1024,7 +1024,6 @@ namespace AzToolsFramework
     static void RefreshUiAfterChange(const EntityIdList& entitiyIds)
     {
         EditorTransformChangeNotificationBus::Broadcast(&EditorTransformChangeNotifications::OnEntityTransformChanged, entitiyIds);
-
         ToolsApplicationNotificationBus::Broadcast(&ToolsApplicationNotificationBus::Events::InvalidatePropertyDisplay, Refresh_Values);
     }
 
@@ -1097,7 +1096,7 @@ namespace AzToolsFramework
         auto entityBoxSelectData = AZStd::make_shared<EntityBoxSelectData>();
 
         m_boxSelect.InstallLeftMouseDown(
-            [this, entityBoxSelectData](const ViewportInteraction::MouseInteractionEvent& /*mouseInteraction*/)
+            [this, entityBoxSelectData]([[maybe_unused]] const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
             {
                 // begin selection undo/redo command
                 entityBoxSelectData->m_boxSelectSelectionCommand =
@@ -1295,8 +1294,12 @@ namespace AzToolsFramework
             });
 
         translationManipulators->InstallLinearManipulatorMouseUpCallback(
-            [this]([[maybe_unused]] const LinearManipulator::Action& action) mutable
+            [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action) mutable
             {
+                AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
+                    &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
+                    manipulatorEntityIds->m_entityIds);
+
                 EndRecordManipulatorCommand();
             });
 
@@ -1325,8 +1328,12 @@ namespace AzToolsFramework
             });
 
         translationManipulators->InstallPlanarManipulatorMouseUpCallback(
-            [this, manipulatorEntityIds](const PlanarManipulator::Action& /*action*/)
+            [this, manipulatorEntityIds]([[maybe_unused]] const PlanarManipulator::Action& action)
             {
+                AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
+                    &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
+                    manipulatorEntityIds->m_entityIds);
+
                 EndRecordManipulatorCommand();
             });
 
@@ -1354,8 +1361,12 @@ namespace AzToolsFramework
             });
 
         translationManipulators->InstallSurfaceManipulatorMouseUpCallback(
-            [this, manipulatorEntityIds](const SurfaceManipulator::Action& /*action*/)
+            [this, manipulatorEntityIds]([[maybe_unused]] const SurfaceManipulator::Action& action)
             {
+                AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
+                    &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
+                    manipulatorEntityIds->m_entityIds);
+
                 EndRecordManipulatorCommand();
             });
 
@@ -1392,7 +1403,7 @@ namespace AzToolsFramework
         AZStd::shared_ptr<SharedRotationState> sharedRotationState = AZStd::make_shared<SharedRotationState>();
 
         rotationManipulators->InstallLeftMouseDownCallback(
-            [this, sharedRotationState](const AngularManipulator::Action& /*action*/) mutable -> void
+            [this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action) mutable -> void
             {
                 sharedRotationState->m_savedOrientation = AZ::Quaternion::CreateIdentity();
                 sharedRotationState->m_referenceFrameAtMouseDown = m_referenceFrame;
@@ -1518,8 +1529,12 @@ namespace AzToolsFramework
             });
 
         rotationManipulators->InstallLeftMouseUpCallback(
-            [this](const AngularManipulator::Action& /*action*/)
+            [this, sharedRotationState]([[maybe_unused]] const AngularManipulator::Action& action)
             {
+                AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
+                    &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
+                    sharedRotationState->m_entityIds);
+
                 EndRecordManipulatorCommand();
             });
 
@@ -1565,6 +1580,10 @@ namespace AzToolsFramework
 
         auto uniformLeftMouseUpCallback = [this, manipulatorEntityIds]([[maybe_unused]] const LinearManipulator::Action& action)
         {
+            AzToolsFramework::EditorTransformChangeNotificationBus::Broadcast(
+                &AzToolsFramework::EditorTransformChangeNotificationBus::Events::OnEntityTransformChanged,
+                manipulatorEntityIds->m_entityIds);
+
             m_entityIdManipulators.m_manipulators->SetLocalTransform(RecalculateAverageManipulatorTransform(
                 m_entityIdManipulators.m_lookups, m_pivotOverrideFrame, m_pivotMode, m_referenceFrame));
         };
@@ -2402,7 +2421,7 @@ namespace AzToolsFramework
 
         AddAction(
             m_actions, { QKeySequence(Qt::Key_U) },
-            /*ID_VIEWPORTUI_VISIBLE=*/50040, "Toggle ViewportUI", "Hide/Unhide Viewport UI",
+            /*ID_VIEWPORTUI_VISIBLE=*/50040, "Toggle Viewport UI", "Hide/Show Viewport UI",
             [this]()
             {
                 SetAllViewportUiVisible(!m_viewportUiVisible);
@@ -3642,17 +3661,17 @@ namespace AzToolsFramework
         RegenerateManipulators();
     }
 
-    void EditorTransformComponentSelection::OnEntityVisibilityChanged(const bool /*visibility*/)
+    void EditorTransformComponentSelection::OnEntityVisibilityChanged([[maybe_unused]] const bool visibility)
     {
         m_selectedEntityIdsAndManipulatorsDirty = true;
     }
 
-    void EditorTransformComponentSelection::OnEntityLockChanged(const bool /*locked*/)
+    void EditorTransformComponentSelection::OnEntityLockChanged([[maybe_unused]] const bool locked)
     {
         m_selectedEntityIdsAndManipulatorsDirty = true;
     }
 
-    void EditorTransformComponentSelection::EnteredComponentMode(const AZStd::vector<AZ::Uuid>& /*componentModeTypes*/)
+    void EditorTransformComponentSelection::EnteredComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentModeTypes)
     {
         SetAllViewportUiVisible(false);
 
@@ -3661,7 +3680,7 @@ namespace AzToolsFramework
         ToolsApplicationNotificationBus::Handler::BusDisconnect();
     }
 
-    void EditorTransformComponentSelection::LeftComponentMode(const AZStd::vector<AZ::Uuid>& /*componentModeTypes*/)
+    void EditorTransformComponentSelection::LeftComponentMode([[maybe_unused]] const AZStd::vector<AZ::Uuid>& componentModeTypes)
     {
         SetAllViewportUiVisible(true);
 

+ 2 - 0
Code/Framework/AzToolsFramework/CMakeLists.txt

@@ -85,6 +85,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
                 AZ::AzManipulatorTestFramework.Static
                 AZ::AzTest
                 AZ::AzQtComponents
+        RUNTIME_DEPENDENCIES
+            3rdParty::Qt::Test
     )
     ly_add_googletest(
         NAME AZ::AzToolsFramework.Tests

+ 37 - 0
Code/Framework/AzToolsFramework/Tests/EditorTransformComponentSelectionTests.cpp

@@ -425,6 +425,43 @@ namespace UnitTest
         EXPECT_TRUE(finalEntityTransform.IsClose(finalTransformWorld, 0.01f));
     }
 
+    TEST_F(EditorTransformComponentSelectionManipulatorTestFixture, TranslatingEntityWithLinearManipulatorNotifiesOnEntityTransformChanged)
+    {
+        EditorEntityComponentChangeDetector editorEntityChangeDetector(m_entity1);
+
+        // the initial starting position of the entity (in front and to the left of the camera)
+        const auto initialTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(-10.0f, 10.0f, 0.0f));
+        // where the entity should end up (in front and to the right of the camera)
+        const auto finalTransformWorld = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 10.0f, 0.0f));
+
+        // calculate the position in screen space of the initial position of the entity
+        const auto initialPositionScreen = AzFramework::WorldToScreen(initialTransformWorld.GetTranslation(), m_cameraState);
+        // calculate the position in screen space of the final position of the entity
+        const auto finalPositionScreen = AzFramework::WorldToScreen(finalTransformWorld.GetTranslation(), m_cameraState);
+
+        // move the entity to its starting position
+        AzToolsFramework::SetWorldTransform(m_entity1, initialTransformWorld);
+        // select the entity (this will cause the manipulators to appear in EditorTransformComponentSelection)
+        AzToolsFramework::SelectEntity(m_entity1);
+
+        // create an offset along the linear manipulator pointing along the x-axis (perpendicular to the camera view)
+        const auto mouseOffsetOnManipulator = AzFramework::ScreenVector(10, 0);
+        // store the mouse down position on the manipulator
+        const auto mouseDownPosition = initialPositionScreen + mouseOffsetOnManipulator;
+        // final position in screen space of the mouse
+        const auto mouseMovePosition = finalPositionScreen + mouseOffsetOnManipulator;
+
+        m_actionDispatcher->CameraState(m_cameraState)
+            ->MousePosition(mouseDownPosition)
+            ->MouseLButtonDown()
+            ->MousePosition(mouseMovePosition)
+            ->MouseLButtonUp();
+
+        // verify a EditorTransformChangeNotificationBus::OnEntityTransformChanged occurred
+        using ::testing::UnorderedElementsAreArray;
+        EXPECT_THAT(editorEntityChangeDetector.m_entityIds, UnorderedElementsAreArray(m_entityIds));
+    }
+
     // simple widget to listen for a mouse wheel event and then forward it on to the ViewportSelectionRequestBus
     class WheelEventWidget : public QWidget
     {

+ 12 - 6
Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/SpawnableCreateBenchmarks.cpp

@@ -29,15 +29,20 @@ namespace Benchmark
             {},
             m_pathString));
 
+
         auto& prefabDom = m_prefabSystemComponent->FindTemplateDom(instance->GetTemplateId());
         for (auto _ : state)
         {
-            state.PauseTiming();
-
-            AzFramework::Spawnable spawnable;
-            AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(spawnable, prefabDom);
-
-            state.ResumeTiming();
+            // Create a vector to store spawnables so that they don't get destroyed immediately after construction.
+            AZStd::vector<AZStd::unique_ptr<AzFramework::Spawnable>> spawnables;
+            spawnables.reserve(numSpawnables);
+            
+            for (int spwanableCounter = 0; spwanableCounter < numSpawnables; ++spwanableCounter)
+            {
+                AZStd::unique_ptr<AzFramework::Spawnable> spawnable = AZStd::make_unique<AzFramework::Spawnable>();
+                AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(*spawnable, prefabDom);
+                spawnables.push_back(AZStd::move(spawnable));
+            }
         }
 
         state.SetComplexityN(numSpawnables);
@@ -50,3 +55,4 @@ namespace Benchmark
 }
 
 #endif
+

+ 37 - 35
Code/Framework/Tests/CMakeLists.txt

@@ -9,7 +9,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #
 
-if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
 
     ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
 
@@ -27,40 +27,42 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
                 AZ::AzFramework
     )
 
-    ly_add_target(
-        NAME ProcessLaunchTest EXECUTABLE
-        NAMESPACE AZ
-        FILES_CMAKE
-            process_launch_test_files.cmake
-        INCLUDE_DIRECTORIES
-            PRIVATE
-                .
-        BUILD_DEPENDENCIES
-            PRIVATE
-                AZ::AzCore
-                AZ::AzFramework
-    )
+    if(PAL_TRAIT_BUILD_HOST_TOOLS)
+        ly_add_target(
+            NAME ProcessLaunchTest EXECUTABLE
+            NAMESPACE AZ
+            FILES_CMAKE
+                process_launch_test_files.cmake
+            INCLUDE_DIRECTORIES
+                PRIVATE
+                    .
+            BUILD_DEPENDENCIES
+                PRIVATE
+                    AZ::AzCore
+                    AZ::AzFramework
+        )
 
-    ly_add_target(
-        NAME Framework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
-        NAMESPACE AZ
-        FILES_CMAKE
-            frameworktests_files.cmake
-        INCLUDE_DIRECTORIES
-            PRIVATE
-                .
-                ${pal_dir}
-        BUILD_DEPENDENCIES
-            PRIVATE
-                AZ::AzTest
-                AZ::AzToolsFramework
-                AZ::AzTestShared
-                AZ::AzFrameworkTestShared
-        RUNTIME_DEPENDENCIES
-            AZ::ProcessLaunchTest
-    )
-    ly_add_googletest(
-        NAME AZ::Framework.Tests
-    )
+        ly_add_target(
+            NAME Framework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
+            NAMESPACE AZ
+            FILES_CMAKE
+                frameworktests_files.cmake
+            INCLUDE_DIRECTORIES
+                PRIVATE
+                    .
+                    ${pal_dir}
+            BUILD_DEPENDENCIES
+                PRIVATE
+                    AZ::AzTest
+                    AZ::AzToolsFramework
+                    AZ::AzTestShared
+                    AZ::AzFrameworkTestShared
+            RUNTIME_DEPENDENCIES
+                AZ::ProcessLaunchTest
+        )
+        ly_add_googletest(
+            NAME AZ::Framework.Tests
+        )
+    endif()
 
 endif()

+ 84 - 0
Code/Framework/Tests/Mocks/MockSpawnableEntitiesInterface.h

@@ -0,0 +1,84 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+#pragma once
+
+#include <AzCore/UnitTest/UnitTest.h>
+#include <gmock/gmock.h>
+#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
+#include <AzFramework/Spawnable/SpawnableEntitiesManager.h>
+
+namespace AzFramework
+{
+    class MockSpawnableEntitiesInterface;
+    using NiceSpawnableEntitiesInterfaceMock = ::testing::NiceMock<MockSpawnableEntitiesInterface>;
+
+    class MockSpawnableEntitiesInterface : public SpawnableEntitiesDefinition
+    {
+    public:
+        AZ_RTTI(MockSpawnableEntitiesInterface, "{2A20FF73-C445-4F32-ABB9-5CF0A5778404}", SpawnableEntitiesDefinition);
+
+        MockSpawnableEntitiesInterface()
+        {
+            AZ::Interface<SpawnableEntitiesDefinition>::Register(this);
+        }
+
+        virtual ~MockSpawnableEntitiesInterface()
+        {
+            AZ::Interface<SpawnableEntitiesDefinition>::Unregister(this);
+        }
+
+        MOCK_METHOD2(SpawnAllEntities, void(EntitySpawnTicket& ticket, SpawnAllEntitiesOptionalArgs optionalArgs));
+
+        MOCK_METHOD3(
+            SpawnEntities,
+            void(EntitySpawnTicket& ticket, AZStd::vector<size_t> entityIndices, SpawnEntitiesOptionalArgs optionalArgs));
+
+        MOCK_METHOD2(DespawnAllEntities, void(EntitySpawnTicket& ticket, DespawnAllEntitiesOptionalArgs optionalArgs));
+
+        MOCK_METHOD3(
+            ReloadSpawnable,
+            void(EntitySpawnTicket& ticket, AZ::Data::Asset<Spawnable> spawnable, ReloadSpawnableOptionalArgs optionalArgs));
+
+        MOCK_METHOD3(
+            ListEntities, void(EntitySpawnTicket& ticket, ListEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs));
+
+        MOCK_METHOD3(
+            ListIndicesAndEntities,
+            void(EntitySpawnTicket& ticket, ListIndicesEntitiesCallback listCallback, ListEntitiesOptionalArgs optionalArgs));
+
+        MOCK_METHOD3(
+            ClaimEntities,
+            void(EntitySpawnTicket& ticket, ClaimEntitiesCallback listCallback, ClaimEntitiesOptionalArgs optionalArgs));
+
+        MOCK_METHOD3(Barrier, void(EntitySpawnTicket& ticket, BarrierCallback completionCallback, BarrierOptionalArgs optionalArgs));
+
+        MOCK_METHOD1(CreateTicket, AZStd::pair<EntitySpawnTicket::Id, void*>(AZ::Data::Asset<Spawnable>&& spawnable));
+        MOCK_METHOD1(DestroyTicket, void(void* ticket));
+
+        /** Installs some default result values for the above functions.
+         *   Note that you can always override these in scope of your test by adding additional ON_CALL / EXPECT_CALL
+         *   statements in the body of your test or after calling this function, and yours will take precedence.
+         **/
+        static void InstallDefaultReturns(NiceSpawnableEntitiesInterfaceMock& target)
+        {
+            using namespace ::testing;
+
+            // The ID and pointer are completely arbitrary, they just need to both be non-zero to look like a valid ticket.
+            constexpr EntitySpawnTicket::Id ticketId(1);
+            static int ticketPayload = 0;
+            ON_CALL(target, CreateTicket(_)).WillByDefault(
+                Return(AZStd::make_pair<AzFramework::EntitySpawnTicket::Id, void*>(ticketId, &ticketPayload)));
+        }
+
+    };
+
+} // namespace AzFramework

+ 1 - 0
Code/Framework/Tests/framework_shared_tests_files.cmake

@@ -10,6 +10,7 @@
 #
 
 set(FILES
+    Mocks/MockSpawnableEntitiesInterface.h
     Utils/Utils.h
     Utils/Utils.cpp
 )

+ 1 - 1
Code/LauncherUnified/launcher_generator.cmake

@@ -26,7 +26,7 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
             message(FATAL_ERROR "The specified project path of ${project_real_path} does not contain a project.json file")
         else()
             # Add the project_name to global LY_PROJECTS_TARGET_NAME property
-            file(READ "${project_real_path}/project.json" project_json)
+            ly_file_read("${project_real_path}/project.json" project_json)
             string(JSON project_name ERROR_VARIABLE json_error GET ${project_json} "project_name")
             if(json_error)
                 message(FATAL_ERROR "There is an error reading the \"project_name\" key from the '${project_real_path}/project.json' file: ${json_error}")

+ 0 - 1
Code/Sandbox/Editor/CMakeLists.txt

@@ -104,7 +104,6 @@ ly_add_target(
             3rdParty::Qt::Gui
             3rdParty::Qt::Widgets
             3rdParty::Qt::Concurrent
-            3rdParty::Qt::WebEngineWidgets
             3rdParty::tiff
             3rdParty::squish-ccr
             3rdParty::zlib

+ 1 - 8
Code/Sandbox/Editor/CryEdit.cpp

@@ -4005,17 +4005,10 @@ void CCryEditApp::SetEditorWindowTitle(QString sTitleStr, QString sPreTitleStr,
 {
     if (MainWindow::instance() || m_pConsoleDialog)
     {
-        QString platform = "";
-
-#ifdef WIN64
-        platform = "[x64]";
-#else
-        platform = "[x86]";
-#endif //WIN64
 
         if (sTitleStr.isEmpty())
         {
-            sTitleStr = QObject::tr("Open 3D Engine Editor Beta %1 - Build %2").arg(platform).arg(LY_BUILD);
+            sTitleStr = QObject::tr("O3DE Editor [Developer Preview]");
         }
 
         if (!sPreTitleStr.isEmpty())

+ 0 - 2
Code/Sandbox/Editor/EditorPreferencesPageAWS.cpp

@@ -47,8 +47,6 @@ CEditorPreferencesPage_AWS::CEditorPreferencesPage_AWS()
 {
     m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
     InitializeSettings();
-
-    // TODO Update with AWS svg.
     m_icon = QIcon(":/res/AWS_preferences_icon.svg");
 }
 

+ 2 - 20
Code/Sandbox/Editor/EditorPreferencesPageGeneral.cpp

@@ -28,8 +28,6 @@
 #define EDITORPREFS_EVENTVALTOGGLE "operation"
 #define UNDOSLICESAVE_VALON "UndoSliceSaveValueOn"
 #define UNDOSLICESAVE_VALOFF "UndoSliceSaveValueOff"
-#define EDITORUI10_ENABLED "EditorUI10On"
-#define EDITORUI10_DISABLED "EditorUI10Off"
 
 void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize)
 {
@@ -45,8 +43,7 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize)
         ->Field("StylusMode", &GeneralSettings::m_stylusMode)
         ->Field("ShowNews", &GeneralSettings::m_bShowNews)
         ->Field("EnableSceneInspector", &GeneralSettings::m_enableSceneInspector)
-        ->Field("RestoreViewportCamera", &GeneralSettings::m_restoreViewportCamera)
-        ->Field("PrefabSystem", &GeneralSettings::m_enablePrefabSystem);
+        ->Field("RestoreViewportCamera", &GeneralSettings::m_restoreViewportCamera);
 
     serialize.Class<Messaging>()
         ->Version(2)
@@ -94,8 +91,7 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize)
                 ->EnumAttribute(AzQtComponents::ToolBar::ToolBarIconSize::IconLarge, "Large")
             ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_stylusMode, "Stylus Mode", "Stylus Mode for tablets and other pointing devices")
             ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_restoreViewportCamera, EditorPreferencesGeneralRestoreViewportCameraSettingName, "Keep the original editor viewport transform when exiting game mode.")
-            ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_enableSceneInspector, "Enable Scene Inspector (EXPERIMENTAL)", "Enable the option to inspect the internal data loaded from scene files like .fbx. This is an experimental feature. Restart the Scene Settings if the option is not visible under the Help menu.")
-            ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_enablePrefabSystem, "Enable Prefab System (EXPERIMENTAL)", "Enable this option to preview Open 3D Engine's new prefab system. Enabling this setting removes slice support for level entities; you will need to restart the Editor for the change to take effect.");
+            ->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_enableSceneInspector, "Enable Scene Inspector (EXPERIMENTAL)", "Enable the option to inspect the internal data loaded from scene files like .fbx. This is an experimental feature. Restart the Scene Settings if the option is not visible under the Help menu.");
 
         editContext->Class<Messaging>("Messaging", "")
             ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Messaging::m_showDashboard, "Show Welcome to Open 3D Engine at startup", "Show Welcome to Open 3D Engine at startup")
@@ -159,8 +155,6 @@ void CEditorPreferencesPage_General::OnApply()
     gSettings.restoreViewportCamera = m_generalSettings.m_restoreViewportCamera;
     gSettings.enableSceneInspector = m_generalSettings.m_enableSceneInspector;
 
-    gSettings.prefabSystem = m_generalSettings.m_enablePrefabSystem;
-
     if (static_cast<int>(m_generalSettings.m_toolbarIconSize) != gSettings.gui.nToolbarIconSize)
     {
         gSettings.gui.nToolbarIconSize = static_cast<int>(m_generalSettings.m_toolbarIconSize);
@@ -178,16 +172,6 @@ void CEditorPreferencesPage_General::OnApply()
 
     //slices
     gSettings.sliceSettings.dynamicByDefault = m_sliceSettings.m_slicesDynamicByDefault;
-
-    // if the user enabled/disabled the prefab context - notify them that a restart
-    // is required in order to see the effect of the change
-    if (gSettings.prefabSystem != m_generalSettings.m_enablePrefabSystemInitialValue)
-    {
-        QMessageBox::warning(
-            AzToolsFramework::GetActiveWindow(), QObject::tr("Restart required"),
-            QObject::tr("Restart the Editor in order for the Prefab/Slice system changes to take effect.")
-        );
-    }
 }
 
 void CEditorPreferencesPage_General::InitializeSettings()
@@ -202,8 +186,6 @@ void CEditorPreferencesPage_General::InitializeSettings()
     m_generalSettings.m_stylusMode = gSettings.stylusMode;
     m_generalSettings.m_restoreViewportCamera = gSettings.restoreViewportCamera;
     m_generalSettings.m_enableSceneInspector = gSettings.enableSceneInspector;
-    m_generalSettings.m_enablePrefabSystem = gSettings.prefabSystem;
-    m_generalSettings.m_enablePrefabSystemInitialValue = gSettings.prefabSystem;
 
     m_generalSettings.m_toolbarIconSize = static_cast<AzQtComponents::ToolBar::ToolBarIconSize>(gSettings.gui.nToolbarIconSize);
 

+ 0 - 4
Code/Sandbox/Editor/EditorPreferencesPageGeneral.h

@@ -58,10 +58,6 @@ private:
         bool m_restoreViewportCamera;
         bool m_bShowNews;
         bool m_enableSceneInspector;
-        bool m_enablePrefabSystem;
-
-        // Only used to tell if the user has changed this value since it requires a restart
-        bool m_enablePrefabSystemInitialValue;
     };
 
     struct Messaging

+ 22 - 5
Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp

@@ -154,11 +154,23 @@ SandboxIntegrationManager::SandboxIntegrationManager()
 {
     // Required to receive events from the Cry Engine undo system
     GetIEditor()->GetUndoManager()->AddListener(this);
+
+    // Only create the PrefabIntegrationManager if prefabs are enabled
+    bool prefabSystemEnabled = false;
+    AzFramework::ApplicationRequests::Bus::BroadcastResult(
+        prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
+    if (prefabSystemEnabled)
+    {
+        m_prefabIntegrationManager = aznew AzToolsFramework::Prefab::PrefabIntegrationManager();
+    }
 }
 
 SandboxIntegrationManager::~SandboxIntegrationManager()
 {
     GetIEditor()->GetUndoManager()->RemoveListener(this);
+
+    delete m_prefabIntegrationManager;
+    m_prefabIntegrationManager = nullptr;
 }
 
 void SandboxIntegrationManager::Setup()
@@ -187,11 +199,16 @@ void SandboxIntegrationManager::Setup()
     AZ_Assert((m_editorEntityUiInterface != nullptr),
         "SandboxIntegrationManager requires a EditorEntityUiInterface instance to be present on Setup().");
 
-    m_prefabIntegrationInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabIntegrationInterface>::Get();
-
-    AZ_Assert(
-        (m_prefabIntegrationInterface != nullptr),
-        "SandboxIntegrationManager requires a PrefabIntegrationInterface instance to be present on Setup().");
+    bool prefabSystemEnabled = false;
+    AzFramework::ApplicationRequests::Bus::BroadcastResult(
+        prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
+    if (prefabSystemEnabled)
+    {
+        m_prefabIntegrationInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabIntegrationInterface>::Get();
+        AZ_Assert(
+            (m_prefabIntegrationInterface != nullptr),
+            "SandboxIntegrationManager requires a PrefabIntegrationInterface instance to be present on Setup().");
+    }
 
     m_editorEntityAPI = AZ::Interface<AzToolsFramework::EditorEntityAPI>::Get();
     AZ_Assert(m_editorEntityAPI, "SandboxIntegrationManager requires an EditorEntityAPI instance to be present on Setup().");

+ 1 - 1
Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h

@@ -305,7 +305,7 @@ private:
 
     bool m_debugDisplayBusImplementationActive = false;
 
-    AzToolsFramework::Prefab::PrefabIntegrationManager m_prefabIntegrationManager;
+    AzToolsFramework::Prefab::PrefabIntegrationManager* m_prefabIntegrationManager = nullptr;
 
     AzToolsFramework::EditorEntityUiInterface* m_editorEntityUiInterface = nullptr;
     AzToolsFramework::Prefab::PrefabIntegrationInterface* m_prefabIntegrationInterface = nullptr;

+ 2 - 1
Code/Tools/AssetBundler/tests/DummyProject/project.json

@@ -10,5 +10,6 @@
         "version_number" : 1,
         "version_name" : "1.0.0.0",
         "orientation" : "landscape"
-    }
+    },
+    "engine" : "o3de"
 }

+ 7 - 6
Code/Tools/AssetProcessor/native/ui/SourceAssetTreeModel.cpp

@@ -63,7 +63,7 @@ namespace AssetProcessor
         }
 
 
-        AZ::IO::Path fullPath = AZ::IO::Path(scanFolder.m_scanFolder, AZ::IO::PosixPathSeparator) / source.m_sourceName;
+        AZ::IO::Path fullPath = AZ::IO::Path(scanFolder.m_scanFolder) / source.m_sourceName;
 
         // It's common for Open 3D Engine game projects and scan folders to be in a subfolder
         // of the engine install. To improve readability of the source files, strip out
@@ -74,7 +74,7 @@ namespace AssetProcessor
         }
         if (m_assetRootSet)
         {
-            AzFramework::StringFunc::Replace(fullPath.Native(), m_assetRoot.absolutePath().toUtf8(), "");
+            fullPath = fullPath.LexicallyProximate(m_assetRoot.absolutePath().toUtf8().constData());
         }
 
         if (fullPath.empty())
@@ -88,11 +88,12 @@ namespace AssetProcessor
         QModelIndex newIndicesStart;
 
         AssetTreeItem* parentItem = m_root.get();
-        AZ::IO::Path currentFullFolderPath;
-        const AZ::IO::PathView filename = fullPath.Filename();
-        const AZ::IO::PathView fullPathWithoutFilename = fullPath.RemoveFilename();
+        // Use posix path separator for each child item
+        AZ::IO::Path currentFullFolderPath(AZ::IO::PosixPathSeparator);
+        const AZ::IO::FixedMaxPath filename = fullPath.Filename();
+        fullPath.RemoveFilename();
         AZStd::fixed_string<AZ::IO::MaxPathLength> currentPath;
-        for (auto pathIt = fullPathWithoutFilename.begin(); pathIt != fullPathWithoutFilename.end(); ++pathIt)
+        for (auto pathIt = fullPath.begin(); pathIt != fullPath.end(); ++pathIt)
         {
             currentPath = pathIt->FixedMaxPathString();
             currentFullFolderPath /= currentPath;

+ 9 - 9
Code/Tools/AssetProcessor/native/utilities/BuilderManager.cpp

@@ -12,6 +12,7 @@
 
 #include "BuilderManager.h"
 #include <AzCore/std/smart_ptr/make_shared.h>
+#include <AzCore/Utils/Utils.h>
 
 #include <AzFramework/API/ApplicationAPI.h>
 #include <native/connection/connectionManager.h>
@@ -186,10 +187,9 @@ namespace AssetProcessor
         QDir projectCacheRoot;
         AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
 
-        QString gameName = AssetUtilities::ComputeProjectName();
-        QString projectPath = AssetUtilities::ComputeProjectPath();
-        QDir engineRoot;
-        AssetUtilities::ComputeEngineRoot(engineRoot);
+        AZ::SettingsRegistryInterface::FixedValueString projectName = AZ::Utils::GetProjectName();
+        AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
+        AZ::IO::FixedMaxPathString enginePath = AZ::Utils::GetEnginePath();
 
         int portNumber = 0;
         ApplicationServerBus::BroadcastResult(portNumber, &ApplicationServerBus::Events::GetServerListeningPort);
@@ -197,14 +197,14 @@ namespace AssetProcessor
         AZStd::string params;
 #if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
         params = AZStd::string::format(
-            R"(-task=%s -id="%s" -project-name="%s" -project-cache-path="%s" -project-path="%s" -engine-path="%s" -port %d)", task,
-            builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(),
-            projectPath.toUtf8().constData(), engineRoot.absolutePath().toUtf8().constData(), portNumber);
+            R"(-task=%s -id="%s" -project-name="%s" -project-cache-path="%s" -project-path="%s" -engine-path="%s" -port %d)",
+            task, builderGuid.c_str(), projectName.c_str(), projectCacheRoot.absolutePath().toUtf8().constData(),
+            projectPath.c_str(), enginePath.c_str(), portNumber);
 #else
         params = AZStd::string::format(
             R"(-task=%s -id="%s" -project-name="\"%s\"" -project-cache-path="\"%s\"" -project-path="\"%s\"" -engine-path="\"%s\"" -port %d)",
-            task, builderGuid.c_str(), gameName.toUtf8().constData(), projectCacheRoot.absolutePath().toUtf8().constData(),
-            projectPath.toUtf8().constData(), engineRoot.absolutePath().toUtf8().constData(), portNumber);
+            task, builderGuid.c_str(), projectName.c_str(), projectCacheRoot.absolutePath().toUtf8().constData(),
+            projectPath.c_str(), enginePath.c_str(), portNumber);
 #endif // !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
 
         if (moduleFilePath && moduleFilePath[0])

+ 6 - 3
Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp

@@ -77,6 +77,7 @@ namespace O3DE::ProjectManager
         return ProjectManagerScreen::CreateProject;
     }
 
+    // Called when pressing "Create New Project"
     void CreateProjectCtrl::NotifyCurrentScreen()
     {
         ScreenWidget* currentScreen = reinterpret_cast<ScreenWidget*>(m_stack->currentWidget());
@@ -84,6 +85,11 @@ namespace O3DE::ProjectManager
         {
             currentScreen->NotifyCurrentScreen();
         }
+
+        // Gather the gems from the project template. When we will have multiple project templates, we need to re-gather them
+        // on changing the template and let the user know that any further changes on top of the template will be lost.
+        QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
+        m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true);
     }
 
     void CreateProjectCtrl::HandleBackButton()
@@ -151,9 +157,6 @@ namespace O3DE::ProjectManager
             {
                 m_stack->setCurrentIndex(m_stack->currentIndex() + 1);
 
-                QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
-                m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true);
-
                 Update();
             }
             else

+ 4 - 3
Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp

@@ -89,17 +89,18 @@ namespace O3DE::ProjectManager
         return ProjectManagerScreen::UpdateProject;
     }
 
+    // Called when pressing "Edit Project Settings..."
     void UpdateProjectCtrl::NotifyCurrentScreen()
     {
         m_stack->setCurrentIndex(ScreenOrder::Settings);
         Update();
+
+        // Gather the available gems that will be shown in the gem catalog.
+        m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false);
     }
 
     void UpdateProjectCtrl::HandleGemsButton()
     {
-        // The next page is the gem catalog. Gather the available gems that will be shown in the gem catalog.
-        m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false);
-
         m_stack->setCurrentWidget(m_gemCatalogScreen);
         Update();
     }

+ 1 - 0
Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp

@@ -77,6 +77,7 @@ namespace AZ
             {
                 AZStd::string extension;
                 StringFunc::Path::GetExtension(path.c_str(), extension);
+                AZStd::to_lower(extension.begin(), extension.end());
                 
                 if (!m_settings.m_supportedFileTypeExtensions.contains(extension))
                 {

+ 1 - 1
Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp

@@ -151,7 +151,7 @@ namespace AZ
                 SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
                 if (serializeContext)
                 {
-                    serializeContext->Class<AssImpAnimationImporter, SceneCore::LoadingComponent>()->Version(4); // [LYN-3971] Bone pruning crash fix in AssImp SDK
+                    serializeContext->Class<AssImpAnimationImporter, SceneCore::LoadingComponent>()->Version(5); // [LYN-4226] Invert PostRotation matrix in animation chains
                 }
             }
 

+ 21 - 9
Code/Tools/SerializeContextTools/SliceConverter.cpp

@@ -385,24 +385,36 @@ namespace AZ
                     return false;
                 }
 
-                // Now, convert the nested slice to a prefab.
-                bool nestedSliceResult = ConvertSliceFile(serializeContext, assetPath, isDryRun);
-                if (!nestedSliceResult)
-                {
-                    AZ_Warning("Convert-Slice", nestedSliceResult, "  Nested slice '%s' could not be converted.", assetPath.c_str());
-                    return false;
-                }
+                // Check to see if we've already converted this slice at a higher level of slice nesting, or if this is our first
+                // occurrence and we need to convert it now.
 
-                // Find the prefab template we created for the newly-created nested prefab.
-                // To get the template, we need to take our absolute slice path and turn it into a project-relative prefab path.
+                // First, take our absolute slice path and turn it into a project-relative prefab path.
                 AZ::IO::Path nestedPrefabPath = assetPath;
                 nestedPrefabPath.ReplaceExtension("prefab");
 
                 auto prefabLoaderInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabLoaderInterface>::Get();
                 nestedPrefabPath = prefabLoaderInterface->GenerateRelativePath(nestedPrefabPath);
 
+                // Now, see if we already have a template ID in memory for it.
                 AzToolsFramework::Prefab::TemplateId nestedTemplateId =
                     prefabSystemComponentInterface->GetTemplateIdFromFilePath(nestedPrefabPath);
+
+                // If we don't have a template ID yet, convert the nested slice to a prefab and get the template ID.
+                if (nestedTemplateId == AzToolsFramework::Prefab::InvalidTemplateId)
+                {
+                    bool nestedSliceResult = ConvertSliceFile(serializeContext, assetPath, isDryRun);
+                    if (!nestedSliceResult)
+                    {
+                        AZ_Warning("Convert-Slice", nestedSliceResult, "  Nested slice '%s' could not be converted.", assetPath.c_str());
+                        return false;
+                    }
+
+                    nestedTemplateId = prefabSystemComponentInterface->GetTemplateIdFromFilePath(nestedPrefabPath);
+                    AZ_Assert(nestedTemplateId != AzToolsFramework::Prefab::InvalidTemplateId,
+                        "Template ID for %s is invalid", nestedPrefabPath.c_str());
+                }
+
+                // Get the nested prefab template.
                 AzToolsFramework::Prefab::TemplateReference nestedTemplate =
                     prefabSystemComponentInterface->FindTemplate(nestedTemplateId);
 

+ 3 - 1
Gems/AWSCore/Code/CMakeLists.txt

@@ -74,7 +74,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
     )
 
     ly_add_target(
-        NAME AWSCore.Editor MODULE
+        NAME AWSCore.Editor GEM_MODULE
         NAMESPACE Gem
         FILES_CMAKE
             awscore_editor_shared_files.cmake
@@ -89,6 +89,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
             Gem::AWSCore
     )
 
+    # This target is not a real gem module
+    # It is not meant to be loaded by the ModuleManager in C++
     ly_add_target(
         NAME AWSCore.ResourceMappingTool MODULE
         NAMESPACE Gem

+ 1 - 1
Gems/AWSCore/Code/Include/Private/Editor/Attribution/AWSAttributionServiceApi.h

@@ -43,7 +43,7 @@ namespace AWSCore
 
             bool UseAWSCredentials()
             {
-                return false;
+                return true;
             }
 
             //! Request body for the service API request.

+ 2 - 4
Gems/AWSCore/Code/Source/Credential/AWSCVarCredentialHandler.cpp

@@ -18,7 +18,6 @@ namespace AWSCore
 {
     AZ_CVAR(AZ::CVarFixedString, cl_awsAccessKey, "", nullptr, AZ::ConsoleFunctorFlags::Null, "Override AWS access key");
     AZ_CVAR(AZ::CVarFixedString, cl_awsSecretKey, "", nullptr, AZ::ConsoleFunctorFlags::Null, "Override AWS secret key");
-    AZ_CVAR(AZ::CVarFixedString, cl_awsSessionToken, "", nullptr, AZ::ConsoleFunctorFlags::Null, "Override AWS session token");
 
     static constexpr char AWSCVARCREDENTIALHANDLER_ALLOC_TAG[] = "AWSCVarCredentialHandler";
 
@@ -43,13 +42,12 @@ namespace AWSCore
     {
         auto accessKey = static_cast<AZ::CVarFixedString>(cl_awsAccessKey);
         auto secretKey = static_cast<AZ::CVarFixedString>(cl_awsSecretKey);
-        auto sessionToken = static_cast<AZ::CVarFixedString>(cl_awsSessionToken);
-        // Session token is not always required
+
         if (!accessKey.empty() && !secretKey.empty())
         {
             AZStd::lock_guard<AZStd::mutex> credentialsLock{m_credentialMutex};
             m_cvarCredentialsProvider = Aws::MakeShared<Aws::Auth::SimpleAWSCredentialsProvider>(
-                AWSCVARCREDENTIALHANDLER_ALLOC_TAG, accessKey.c_str(), secretKey.c_str(), sessionToken.c_str());
+                AWSCVARCREDENTIALHANDLER_ALLOC_TAG, accessKey.c_str(), secretKey.c_str());
             return m_cvarCredentialsProvider;
         }
         return nullptr;

+ 19 - 12
Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp

@@ -25,20 +25,24 @@
 #include <AzCore/Module/ModuleManagerBus.h>
 #include <ResourceMapping/AWSResourceMappingUtils.h>
 
+#include <QSysInfo>
+#include <QString>
+
 
 
 namespace AWSCore
 {
-    static constexpr const char* EngineVersionJsonKey = "O3DEVersion";
+    constexpr const char* EngineVersionJsonKey = "O3DEVersion";
 
     constexpr char EditorAWSPreferencesFileName[] = "editor_aws_preferences.setreg";
     constexpr char AWSAttributionSettingsPrefixKey[] = "/Amazon/AWS/Preferences";
     constexpr char AWSAttributionEnabledKey[] = "/Amazon/AWS/Preferences/AWSAttributionEnabled";
     constexpr char AWSAttributionDelaySecondsKey[] = "/Amazon/AWS/Preferences/AWSAttributionDelaySeconds";
     constexpr char AWSAttributionLastTimeStampKey[] = "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp";
-    constexpr char AWSAttributionApiId[] = "xbzx78kvbk";
+    constexpr char AWSAttributionApiId[] = "2zxvvmv8d7";
     constexpr char AWSAttributionChinaApiId[] = "";
     constexpr char AWSAttributionApiStage[] = "prod";
+    const int AWSAttributionDefaultDelayInDays = 7;
 
     AWSAttributionManager::AWSAttributionManager()
     {
@@ -58,12 +62,11 @@ namespace AWSCore
     {
         if (ShouldGenerateMetric())
         {
-            // 1. Gather metadata and assemble metric
+            // Gather metadata and assemble metric
             AttributionMetric metric;
             UpdateMetric(metric);            
-            // 2. Identify region and chose attribution endpoint
             
-            // 3. Post metric
+            // Post metric
             SubmitMetric(metric);
         }
     }
@@ -104,8 +107,7 @@ namespace AWSCore
         AZ::u64 delayInSeconds = 0;
         if (!m_settingsRegistry->Get(delayInSeconds, AWSAttributionDelaySecondsKey))
         {
-            AZ_Warning("AWSAttributionManager", false, "AWSAttribution delay key not found. Defaulting to delay to day");
-            delayInSeconds = 86400;
+            delayInSeconds = 86400 * AWSAttributionDefaultDelayInDays;
             m_settingsRegistry->Set(AWSAttributionDelaySecondsKey, delayInSeconds);
         }
 
@@ -243,7 +245,8 @@ namespace AWSCore
         metric.SetO3DEVersion(engineVersion);
 
         AZStd::string platform = this->GetPlatform();
-        metric.SetPlatform(platform, "");
+        QString productName = QSysInfo::prettyProductName();
+        metric.SetPlatform(platform, productName.toStdString().c_str());
 
         AZStd::vector<AZStd::string> gemNames;
         GetActiveAWSGems(gemNames);
@@ -256,17 +259,21 @@ namespace AWSCore
     void AWSAttributionManager::SubmitMetric(AttributionMetric& metric)
     {
         AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config = ServiceAPI::AWSAttributionRequestJob::GetDefaultConfig();
+        // Identify region and chose attribution endpoint
         SetApiEndpointAndRegion(config);
 
         ServiceAPI::AWSAttributionRequestJob* requestJob = ServiceAPI::AWSAttributionRequestJob::Create(
-            [this](ServiceAPI::AWSAttributionRequestJob* successJob)
+            [this]([[maybe_unused]] ServiceAPI::AWSAttributionRequestJob* successJob)
             {
-                AZ_UNUSED(successJob);
-                
                 UpdateLastSend();
                 AZ_Printf("AWSAttributionManager", "AWSAttribution metric submit success");
 
-            }, {}, config);
+            },
+            [this]([[maybe_unused]] ServiceAPI::AWSAttributionRequestJob* failJob)
+            {
+                AZ_Error("AWSAttributionManager", false, "Metrics send error: %s", failJob->error.message.c_str());
+            },
+            config);
 
         requestJob->parameters.metric = metric;
         requestJob->Start();

+ 4 - 2
Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionMetric.cpp

@@ -19,14 +19,16 @@
 
 namespace AWSCore
 {
+    constexpr char AWSAttributionMetricDefaultO3DEVersion[] = "1.1";
+
     AttributionMetric::AttributionMetric(const AZStd::string& timestamp)
-        : m_version("1.1")
+        : m_version(AWSAttributionMetricDefaultO3DEVersion)
         , m_timestamp(timestamp)
     {
     }
 
     AttributionMetric::AttributionMetric()
-        : m_version("1.1")
+        : m_version(AWSAttributionMetricDefaultO3DEVersion)
     {
         m_timestamp = AttributionMetric::GenerateTimeStamp();
     }

+ 3 - 0
Gems/AWSCore/Code/Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp

@@ -32,6 +32,8 @@
 #include <AzCore/Module/ModuleManagerBus.h>
 
 #include <TestFramework/AWSCoreFixture.h>
+#include <QSysInfo>
+#include <QString>
 
 
 using namespace AWSCore;
@@ -405,6 +407,7 @@ namespace AWSAttributionUnitTest
         AZStd::string serializedMetricValue = metric.SerializeToJson();
         ASSERT_TRUE(serializedMetricValue.find("\"o3de_version\":\"1.0.0.0\"") != AZStd::string::npos);
         ASSERT_TRUE(serializedMetricValue.find(AZ::GetPlatformName(AZ::g_currentPlatform)) != AZStd::string::npos);
+        ASSERT_TRUE(serializedMetricValue.find(QSysInfo::prettyProductName().toStdString().c_str()) != AZStd::string::npos);
         ASSERT_TRUE(serializedMetricValue.find("AWSCore.Editor") != AZStd::string::npos);
         ASSERT_TRUE(serializedMetricValue.find("AWSClientAuth") != AZStd::string::npos);
 

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů