diff --git a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
index 0d6fe4c8fa..ff3cd5c465 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
@@ -6,12 +6,7 @@
#
#
-################################################################################
-# Atom Renderer: Automated Tests
-# Runs EditorPythonBindings (hydra) scripts inside the Editor to verify test results for the Atom renderer.
-################################################################################
-
-if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS)
+if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_pytest(
NAME AutomatedTesting::Atom_TestSuite_Main
TEST_SUITE main
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
index 3403d8e9b1..220623af8b 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
@@ -220,20 +220,18 @@ class TestPerformanceBenchmarkSuite(object):
@pytest.mark.system
class TestMaterialEditor(object):
- @pytest.mark.parametrize("cfg_args", ["-rhi=dx12", "-rhi=Vulkan"])
+ @pytest.mark.parametrize("cfg_args,expected_lines", [
+ pytest.param("-rhi=dx12", ["Registering dx12 RHI"]),
+ pytest.param("-rhi=Vulkan", ["Registering vulkan RHI"])
+ ])
@pytest.mark.parametrize("exe_file_name", ["MaterialEditor"])
def test_MaterialEditorLaunch_AllRHIOptionsSucceed(
- self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args):
+ self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args,
+ expected_lines):
"""
Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor.
- Checks for the "Finished loading viewport configurations." success message post launch.
+ Checks for the specific expected_lines messaging for each RHI type.
"""
- expected_lines = ["Finished loading viewport configurations."]
- unexpected_lines = [
- # "Trace::Assert",
- # "Trace::Error",
- "Traceback (most recent call last):",
- ]
hydra.launch_and_validate_results(
request,
@@ -243,7 +241,7 @@ class TestMaterialEditor(object):
run_python="--runpython",
timeout=60,
expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
+ unexpected_lines=[],
halt_on_unexpected=False,
null_renderer=False,
cfg_args=[cfg_args],
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
index f5ac411a01..90436fbe27 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
@@ -14,36 +14,50 @@ from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAutomation(EditorTestSuite):
+ @pytest.mark.test_case_id("C32078118")
class AtomEditorComponents_DecalAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
+ @pytest.mark.test_case_id("C32078119")
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
+ @pytest.mark.test_case_id("C32078120")
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
+ @pytest.mark.test_case_id("C32078121")
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
+ @pytest.mark.test_case_id("C32078115")
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
+ @pytest.mark.test_case_id("C32078125")
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
+ @pytest.mark.test_case_id("C32078131")
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
from Atom.tests import (
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
+ @pytest.mark.test_case_id("C32078117")
class AtomEditorComponents_LightAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
+ @pytest.mark.test_case_id("C36525660")
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
+ @pytest.mark.test_case_id("C32078128")
class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
+ @pytest.mark.test_case_id("C32078124")
+ class AtomEditorComponents_MeshAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
+
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py
new file mode 100644
index 0000000000..fbf5c987d1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py
@@ -0,0 +1,171 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+
+class Tests:
+ creation_undo = (
+ "UNDO Entity creation success",
+ "UNDO Entity creation failed")
+ creation_redo = (
+ "REDO Entity creation success",
+ "REDO Entity creation failed")
+ mesh_entity_creation = (
+ "Mesh Entity successfully created",
+ "Mesh Entity failed to be created")
+ mesh_component_added = (
+ "Entity has a Mesh component",
+ "Entity failed to find Mesh component")
+ mesh_asset_specified = (
+ "Mesh asset set",
+ "Mesh asset not set")
+ enter_game_mode = (
+ "Entered game mode",
+ "Failed to enter game mode")
+ exit_game_mode = (
+ "Exited game mode",
+ "Couldn't exit game mode")
+ is_visible = (
+ "Entity is visible",
+ "Entity was not visible")
+ is_hidden = (
+ "Entity is hidden",
+ "Entity was not hidden")
+ entity_deleted = (
+ "Entity deleted",
+ "Entity was not deleted")
+ deletion_undo = (
+ "UNDO deletion success",
+ "UNDO deletion failed")
+ deletion_redo = (
+ "REDO deletion success",
+ "REDO deletion failed")
+
+
+def AtomEditorComponents_Mesh_AddedToEntity():
+ """
+ Summary:
+ Tests the Mesh component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Mesh entity with no components.
+ 2) Add a Mesh component to Mesh entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Specify the Mesh component asset
+ 6) Enter/Exit game mode.
+ 7) Test IsHidden.
+ 8) Test IsVisible.
+ 9) Delete Mesh entity.
+ 10) UNDO deletion.
+ 11) REDO deletion.
+ 12) Look for errors.
+
+ :return: None
+ """
+
+ import os
+
+ import azlmbr.legacy.general as general
+
+ from editor_python_test_tools.asset_utils import Asset
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Mesh entity with no components.
+ mesh_name = "Mesh"
+ mesh_entity = EditorEntity.create_editor_entity(mesh_name)
+ Report.critical_result(Tests.mesh_entity_creation, mesh_entity.exists())
+
+ # 2. Add a Mesh component to Mesh entity.
+ mesh_component = mesh_entity.add_component(mesh_name)
+ Report.critical_result(
+ Tests.mesh_component_added,
+ mesh_entity.has_component(mesh_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not mesh_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, mesh_entity.exists())
+
+ # 5. Set Mesh component asset property
+ mesh_property_asset = 'Controller|Configuration|Mesh Asset'
+ model_path = os.path.join('Objects', 'shaderball', 'shaderball_default_1m.azmodel')
+ model = Asset.find_asset_by_path(model_path)
+ mesh_component.set_component_property_value(mesh_property_asset, model.id)
+ Report.result(Tests.mesh_asset_specified,
+ mesh_component.get_component_property_value(mesh_property_asset) == model.id)
+
+ # 6. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 7. Test IsHidden.
+ mesh_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, mesh_entity.is_hidden() is True)
+
+ # 8. Test IsVisible.
+ mesh_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, mesh_entity.is_visible() is True)
+
+ # 9. Delete Mesh entity.
+ mesh_entity.delete()
+ Report.result(Tests.entity_deleted, not mesh_entity.exists())
+
+ # 10. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, mesh_entity.exists())
+
+ # 11. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not mesh_entity.exists())
+
+ # 12. Look for errors or asserts.
+ helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
+ for error_info in error_tracer.errors:
+ Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
+ for assert_info in error_tracer.asserts:
+ Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_Mesh_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py
index da89316993..e5dd9adbb9 100755
--- a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py
@@ -525,10 +525,6 @@ class TestAutomation(TestAutomationBase):
from .tests.joints import Joints_BallNoLimitsConstrained as test_module
self._run_test(request, workspace, editor, test_module)
- def test_Joints_FixedLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
- from .tests.joints import Joints_FixedLeadFollowerCollide as test_module
- self._run_test(request, workspace, editor, test_module)
-
def test_Joints_GlobalFrameConstrained(self, request, workspace, editor, launcher_platform):
from .tests.joints import Joints_GlobalFrameConstrained as test_module
self._run_test(request, workspace, editor, test_module)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py
index abc58779a2..e949d2d8f9 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_SplineRegionWithModifiedTransform.py
@@ -82,7 +82,7 @@ def ForceRegion_SplineRegionWithModifiedTransform():
import azlmbr.bus as bus
# region Constants
- TIMEOUT = 5.0
+ TIMEOUT = 10.0
MIN_TRIGGER_DISTANCE = 2.0
# endregion
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py
index 91190f83e5..6582628ff9 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/force_region/ForceRegion_ZeroPointForceDoesNothing.py
@@ -77,7 +77,7 @@ def ForceRegion_ZeroPointForceDoesNothing():
helper.init_idle()
- TIMEOUT_SECONDS = 3.0
+ TIMEOUT_SECONDS = 5.0
X_Y_Z_TOLERANCE = 1.5
REGION_HEIGHT = 3.0
TERRAIN_HEIGHT = 32.0
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py
index 6226f42534..a85e460659 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/JointsHelper.py
@@ -45,8 +45,13 @@ class JointEntity:
# Entity class that sets a flag when an instance receives collision events.
class JointEntityCollisionAware(JointEntity):
def on_collision_begin(self, args):
- if not self.collided:
- self.collided = True
+ self.collided = True
+
+ def on_collision_persist(self, args):
+ self.collided = True
+
+ def on_collision_end(self, args):
+ self.collided = True
def __init__(self, name):
self.id = general.find_game_entity(name)
@@ -58,3 +63,5 @@ class JointEntityCollisionAware(JointEntity):
self.handler = azlmbr.physics.CollisionNotificationBusHandler()
self.handler.connect(self.id)
self.handler.add_callback("OnCollisionBegin", self.on_collision_begin)
+ self.handler.add_callback("OnCollisionPresist", self.on_collision_persist)
+ self.handler.add_callback("OnCollisionEnd", self.on_collision_end)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py
deleted file mode 100644
index e142941c5a..0000000000
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py
+++ /dev/null
@@ -1,92 +0,0 @@
-"""
-Copyright (c) Contributors to the Open 3D Engine Project.
-For complete copyright and license terms please see the LICENSE at the root of this distribution.
-
-SPDX-License-Identifier: Apache-2.0 OR MIT
-"""
-
-# Test case ID : C18243582
-# Test Case Title : Check that fixed joint allows lead-follower collision
-
-
-# fmt: off
-class Tests:
- enter_game_mode = ("Entered game mode", "Failed to enter game mode")
- exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
- lead_found = ("Found lead", "Did not find lead")
- follower_found = ("Found follower", "Did not find follower")
- check_collision_happened = ("Lead and follower collided", "Lead and follower did not collide")
-# fmt: on
-
-
-def Joints_FixedLeadFollowerCollide():
- """
- Summary: Check that fixed joint allows lead-follower collision
-
- Level Description:
- lead - Starts above follower entity
- follower - Starts below lead entity. Constrained to lead entity with fixed joint. Starts with initial velocity of (5, 0, 0) in positive X direction.
-
- Expected Behavior:
- The follower entity moves in the positive X direction and the lead entity is dragged along towards the positive X direction.
- The x position of the lead entity is incremented from its original.
- The lead and follower entities are kept apart at a distance of approximately 1.0 due to collision.
-
- Test Steps:
- 1) Open Level
- 2) Enter Game Mode
- 3) Create and Validate Entities
- 4) Wait for several seconds
- 5) Check to see if lead and follower behaved as expected.
- 6) Exit Game Mode
- 7) Close Editor
-
- Note:
- - This test file must be called from the Open 3D Engine Editor command terminal
- - Any passed and failed tests are written to the Editor.log file.
- Parsing the file or running a log_monitor are required to observe the test results.
-
- :return: None
- """
- import os
- import sys
- from editor_python_test_tools.utils import Report
- from editor_python_test_tools.utils import TestHelper as helper
-
- import azlmbr.legacy.general as general
- import azlmbr.bus
-
- from JointsHelper import JointEntityCollisionAware
-
- # Helper Entity class - self.collided flag is set when instance receives collision event.
- class Entity(JointEntityCollisionAware):
- def criticalEntityFound(self): # Override function to use local Test dictionary
- Report.critical_result(Tests.__dict__[self.name + "_found"], self.id.isValid())
-
- # Main Script
- helper.init_idle()
-
- # 1) Open Level
- helper.open_level("Physics", "Joints_FixedLeadFollowerCollide")
-
- # 2) Enter Game Mode
- helper.enter_game_mode(Tests.enter_game_mode)
-
- # 3) Create and Validate Entities
- lead = Entity("lead")
- follower = Entity("follower")
-
- # 4) Wait for several seconds
- general.idle_wait(2.0) # wait for lead and follower to move
-
- # 5) Check to see if lead entity and follower collided
- Report.critical_result(Tests.check_collision_happened, lead.collided and follower.collided)
-
- # 6) Exit Game Mode
- helper.exit_game_mode(Tests.exit_game_mode)
-
-
-
-if __name__ == "__main__":
- from editor_python_test_tools.utils import Report
- Report.start_test(Joints_FixedLeadFollowerCollide)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py
index 1c53854bab..05671389c2 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/rigid_body/RigidBody_KinematicModeWorks.py
@@ -80,6 +80,20 @@ def RigidBody_KinematicModeWorks():
ramp_id = general.find_game_entity("Ramp")
Report.result(Tests.find_ramp, ramp_id.IsValid())
+ # 2.1) setup collision handler
+ class RampTouched:
+ value = False
+
+ def on_collision_begin(args):
+ other_id = args[0]
+ if other_id.Equal(ramp_id):
+ Report.info("Box touched ramp")
+ RampTouched.value = True
+
+ handler = azlmbr.physics.CollisionNotificationBusHandler()
+ handler.connect(box_id)
+ handler.add_callback("OnCollisionBegin", on_collision_begin)
+
# 3) Check for kinematic ramp and not kinematic box
box_kinematic = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsKinematic", box_id)
Report.result(Tests.box_is_not_kinematic, not box_kinematic)
@@ -98,21 +112,7 @@ def RigidBody_KinematicModeWorks():
ramp_pos_start = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", ramp_id)
Report.info("Ramp's initial position: {}".format(ramp_pos_start))
- # 6) Check to see that the box hits the ramp
- class RampTouched:
- value = False
-
- def on_collision_begin(args):
- other_id = args[0]
- if other_id.Equal(ramp_id):
- Report.info("Box touched ramp")
- RampTouched.value = True
-
- handler = azlmbr.physics.CollisionNotificationBusHandler()
- handler.connect(box_id)
- handler.add_callback("OnCollisionBegin", on_collision_begin)
-
- # 6.5) Wait for the box to touch the ramp or timeout
+ # 6) Wait for the box to touch the ramp or timeout
helper.wait_for_condition(lambda: RampTouched.value, TIME_OUT)
Report.result(Tests.box_touched_ramp, RampTouched.value)
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly
deleted file mode 100644
index 0c3ac9e668..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:3093fee5317ba6fb353a435c09f43f13c5e722421aae62a297f699c202d6129e
-size 6699
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml
deleted file mode 100644
index d0960f8154..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak
deleted file mode 100644
index 532be2c1bd..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:b1daa050e732ff0594601bbfca8ac9ed05972c2f9fa3e43dbc8645e802ed2730
-size 7959
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml
deleted file mode 100644
index 4ba36f66ae..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml
deleted file mode 100644
index f43df05b22..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml
deleted file mode 100644
index 456d609b8a..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml
+++ /dev/null
@@ -1,356 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat
deleted file mode 100644
index dce5631cd0..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:0e6a5435c928079b27796f6b202bbc2623e7e454244ddc099a3cadf33b7cb9e9
-size 63
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt
deleted file mode 100644
index 0d6c1880e7..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
-0,0,0,0,0,0
diff --git a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak b/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak
deleted file mode 100644
index fe3604a050..0000000000
--- a/AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85
-size 22
diff --git a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly
index 3d17ae7ccc..86dd941423 100644
--- a/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly
+++ b/AutomatedTesting/Levels/Physics/Joints_HingeNoLimitsConstrained/Joints_HingeNoLimitsConstrained.ly
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:012caffa9354f6253d2e626ba183b44eb02a74eba286fde0430227ef024411e2
-size 8961
+oid sha256:817bd8dd22e185136418b60fba5b3552993687515d3d5ae96791f2c3be907b92
+size 7233
diff --git a/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly b/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly
index 92e6788bf0..d6052ffa7c 100644
--- a/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly
+++ b/AutomatedTesting/Levels/Physics/RigidBody_KinematicModeWorks/RigidBody_KinematicModeWorks.ly
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:619bcf0c2a2b08f4ffe05e60858c479828fe39d5530f4e488b9c0ec8a585ccb7
-size 7735
+oid sha256:cb97ada674d123c67d7a32eb65e81fa66472cf51f748054c4a4297649f2a0f40
+size 5568
diff --git a/Code/Framework/AzCore/AzCore/Console/Console.cpp b/Code/Framework/AzCore/AzCore/Console/Console.cpp
index a1b8a1759d..9f207d9afd 100644
--- a/Code/Framework/AzCore/AzCore/Console/Console.cpp
+++ b/Code/Framework/AzCore/AzCore/Console/Console.cpp
@@ -476,15 +476,16 @@ namespace AZ
// Responsible for using the Json Serialization Issue Callback system
// to determine when a JSON Patch or JSON Merge Patch modifies a value
- // at a path underneath the IConsole::ConsoleRootCommandKey JSON pointer
+ // at a path underneath the IConsole::ConsoleRuntimeCommandKey JSON pointer
JsonSerializationResult::ResultCode operator()(AZStd::string_view message,
JsonSerializationResult::ResultCode result, AZStd::string_view path)
{
- AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator };
+ constexpr AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRuntimeCommandKey, AZ::IO::PosixPathSeparator };
+ constexpr AZ::IO::PathView consoleAutoexecCommandKey{ IConsole::ConsoleAutoexecCommandKey, AZ::IO::PosixPathSeparator };
AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator };
if (result.GetTask() == JsonSerializationResult::Tasks::Merge
&& result.GetProcessing() == JsonSerializationResult::Processing::Completed
- && inputKey.IsRelativeTo(consoleRootCommandKey))
+ && (inputKey.IsRelativeTo(consoleRootCommandKey) || inputKey.IsRelativeTo(consoleAutoexecCommandKey)))
{
if (auto type = m_settingsRegistry.GetType(path); type != SettingsRegistryInterface::Type::NoType)
{
@@ -510,12 +511,24 @@ namespace AZ
{
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
- AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator };
+ constexpr AZ::IO::PathView consoleRuntimeCommandKey{ IConsole::ConsoleRuntimeCommandKey, AZ::IO::PosixPathSeparator };
+ constexpr AZ::IO::PathView consoleAutoexecCommandKey{ IConsole::ConsoleAutoexecCommandKey, AZ::IO::PosixPathSeparator };
AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator };
- // The ConsoleRootComamndKey is not a command itself so strictly children keys are being examined
- if (inputKey.IsRelativeTo(consoleRootCommandKey) && inputKey != consoleRootCommandKey)
+
+ // Abuses the IsRelativeToFuncton function of the path class to extract the console
+ // command from the settings registry objects
+ FixedValueString command;
+ if (inputKey != consoleRuntimeCommandKey && inputKey.IsRelativeTo(consoleRuntimeCommandKey))
+ {
+ command = inputKey.LexicallyRelative(consoleRuntimeCommandKey).Native();
+ }
+ else if (inputKey != consoleAutoexecCommandKey && inputKey.IsRelativeTo(consoleAutoexecCommandKey))
+ {
+ command = inputKey.LexicallyRelative(consoleAutoexecCommandKey).Native();
+ }
+
+ if (!command.empty())
{
- FixedValueString command = inputKey.LexicallyRelative(consoleRootCommandKey).Native();
ConsoleCommandContainer commandArgs;
// Argument string which stores the value from the Settings Registry long enough
// to pass into the PerformCommand. The ConsoleCommandContainer stores string_views
@@ -603,9 +616,10 @@ namespace AZ
void Console::RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry)
{
- // Make sure the there is a JSON object at the path of AZ::IConsole::ConsoleRootCommandKey
+ // Make sure the there is a JSON object at the ConsoleRuntimeCommandKey or ConsoleAutoexecKey
// So that JSON Patch is able to add values underneath that object (JSON Patch doesn't create intermediate objects)
- settingsRegistry.MergeSettings(R"({ "Amazon": { "AzCore": { "Runtime": { "ConsoleCommands": {} } }}})",
+ settingsRegistry.MergeSettings(R"({ "Amazon": { "AzCore": { "Runtime": { "ConsoleCommands": {} } } })"
+ R"(,"O3DE": { "Autoexec": { "ConsoleCommands": {} } } })",
SettingsRegistryInterface::Format::JsonMergePatch);
m_consoleCommandKeyHandler = settingsRegistry.RegisterNotifier(ConsoleCommandKeyNotificationHandler{ settingsRegistry, *this });
diff --git a/Code/Framework/AzCore/AzCore/Console/IConsole.h b/Code/Framework/AzCore/AzCore/Console/IConsole.h
index dafc284ce3..73d17ac65a 100644
--- a/Code/Framework/AzCore/AzCore/Console/IConsole.h
+++ b/Code/Framework/AzCore/AzCore/Console/IConsole.h
@@ -31,7 +31,8 @@ namespace AZ
using FunctorVisitor = AZStd::function;
- inline static constexpr AZStd::string_view ConsoleRootCommandKey = "/Amazon/AzCore/Runtime/ConsoleCommands";
+ inline static constexpr AZStd::string_view ConsoleRuntimeCommandKey = "/Amazon/AzCore/Runtime/ConsoleCommands";
+ inline static constexpr AZStd::string_view ConsoleAutoexecCommandKey = "/O3DE/Autoexec/ConsoleCommands";
IConsole() = default;
virtual ~IConsole() = default;
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
index 3dc1be87c5..40022bdc04 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
@@ -204,14 +204,14 @@ namespace AZ
[[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(const PreMergeEventCallback& callback) = 0;
//! Register a function that will be called before a file is merged.
//! @callback The function to call before a file is merged.
- [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent (PreMergeEventCallback&& callback) = 0;
+ [[nodiscard]] virtual PreMergeEventHandler RegisterPreMergeEvent(PreMergeEventCallback&& callback) = 0;
//! Register a function that will be called after a file is merged.
//! @callback The function to call after a file is merged.
[[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(const PostMergeEventCallback& callback) = 0;
//! Register a function that will be called after a file is merged.
//! @callback The function to call after a file is merged.
- [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent (PostMergeEventCallback&& callback) = 0;
+ [[nodiscard]] virtual PostMergeEventHandler RegisterPostMergeEvent(PostMergeEventCallback&& callback) = 0;
//! Gets the boolean value at the provided path.
//! @param result The target to write the result to.
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp
new file mode 100644
index 0000000000..9456616024
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+
+namespace AZ::SettingsRegistryVisitorUtils
+{
+ // Field Visitor implementation
+ FieldVisitor::FieldVisitor() = default;
+ FieldVisitor::FieldVisitor(VisitFieldType visitFieldType)
+ : m_visitFieldType{ visitFieldType }
+ {
+ }
+
+ auto FieldVisitor::Traverse(AZStd::string_view path, AZStd::string_view valueName,
+ VisitAction action, Type type) -> VisitResponse
+ {
+ // A default response skip prevents visiting grand children(depth 2 or lower)
+ VisitResponse visitResponse = VisitResponse::Skip;
+ if (action == VisitAction::Begin)
+ {
+ // Invoke FieldVisitor override if the root path has been set
+ if (m_rootPath.has_value())
+ {
+ Visit(path, valueName, type);
+ }
+ // To make sure only the direct children are visited(depth 1)
+ // set the root path once and set the VisitReponsoe
+ // to Continue to recurse into is fields
+ if (!m_rootPath.has_value())
+ {
+ bool visitableFieldType{};
+ switch (m_visitFieldType)
+ {
+ case VisitFieldType::Array:
+ visitableFieldType = type == Type::Array;
+ break;
+ case VisitFieldType::Object:
+ visitableFieldType = type == Type::Object;
+ break;
+ case VisitFieldType::ArrayOrObject:
+ visitableFieldType = type == Type::Array || type ==Type::Object;
+ break;
+ default:
+ AZ_Error("FieldVisitor", false, "The field visitation type value is invalid");
+ break;
+ }
+
+ if (visitableFieldType)
+ {
+ m_rootPath = path;
+ visitResponse = VisitResponse::Continue;
+ }
+ }
+ }
+ else if (action == VisitAction::Value)
+ {
+ // Invoke FieldVisitor override if the root path has been set
+ if (m_rootPath.has_value())
+ {
+ Visit(path, valueName, type);
+ }
+ }
+ else if (action == VisitAction::End)
+ {
+ // Reset m_rootPath back to null when the root path has finished being visited
+ if (m_rootPath.has_value() && *m_rootPath == path)
+ {
+ m_rootPath = AZStd::nullopt;
+ }
+ }
+
+
+ return visitResponse;
+ }
+
+ // Array Visitor implementation
+ ArrayVisitor::ArrayVisitor()
+ : FieldVisitor(VisitFieldType::Array)
+ {
+ }
+
+ // Object Visitor implementation
+ ObjectVisitor::ObjectVisitor()
+ : FieldVisitor(VisitFieldType::Object)
+ {
+ }
+
+ // Generic VisitField Callback implemention
+ template
+ bool VisitFieldCallback(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path)
+ {
+ struct VisitFieldVisitor
+ : BaseVisitor
+ {
+ using BaseVisitor::Visit;
+ VisitFieldVisitor(const VisitorCallback& visitCallback)
+ : m_visitCallback{ visitCallback }
+ {}
+
+ void Visit(AZStd::string_view path, AZStd::string_view fieldIndex, typename BaseVisitor::Type type) override
+ {
+ m_visitCallback(path, fieldIndex, type);
+ }
+
+ const VisitorCallback& m_visitCallback;
+ };
+
+ VisitFieldVisitor visitor{ visitCallback };
+ return settingsRegistry.Visit(visitor, path);
+ }
+
+ // VisitField implementation
+ bool VisitField(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path)
+ {
+ return VisitFieldCallback(settingsRegistry, visitCallback, path);
+ }
+
+ // VisitArray implementation
+ bool VisitArray(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path)
+ {
+ return VisitFieldCallback(settingsRegistry, visitCallback, path);
+ }
+
+ // VisitObject implementation
+ bool VisitObject(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path)
+ {
+ return VisitFieldCallback(settingsRegistry, visitCallback, path);
+ }
+}
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h
new file mode 100644
index 0000000000..a45712521f
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include
+
+
+namespace AZ::SettingsRegistryVisitorUtils
+{
+ //! Interface for visiting the fields of an array or object
+ //! To access the values, use the SettingsRegistryInterface Get/GetObject methods
+ struct FieldVisitor
+ : public AZ::SettingsRegistryInterface::Visitor
+ {
+ using VisitResponse = AZ::SettingsRegistryInterface::VisitResponse;
+ using VisitAction = AZ::SettingsRegistryInterface::VisitAction;
+ using Type = AZ::SettingsRegistryInterface::Type;
+
+ FieldVisitor();
+
+ // Bring the base class visitor functions into scope
+ using AZ::SettingsRegistryInterface::Visitor::Visit;
+ virtual void Visit(AZStd::string_view path, AZStd::string_view arrayIndex, Type type) = 0;
+
+ protected:
+ // VisitFieldType is used for filtering the type of referenced by the root path
+ enum class VisitFieldType
+ {
+ Array,
+ Object,
+ ArrayOrObject
+ };
+ FieldVisitor(const VisitFieldType visitFieldType);
+ private:
+ VisitResponse Traverse(AZStd::string_view path, AZStd::string_view valueName,
+ VisitAction action, Type type) override;
+
+ VisitFieldType m_visitFieldType{ VisitFieldType::ArrayOrObject };
+ AZStd::optional m_rootPath;
+ };
+
+ //! Interface for visiting the fields of an array
+ //! To access the values, use the SettingsRegistryInterface Get/GetObject methods
+ struct ArrayVisitor
+ : public FieldVisitor
+ {
+ ArrayVisitor();
+ };
+
+ //! Interface for visiting the fields of an object
+ //! To access the values, use the SettingsRegistryInterface Get/GetObject methods
+ struct ObjectVisitor
+ : public FieldVisitor
+ {
+ ObjectVisitor();
+ };
+
+ //! Signature of callback funcition invoked when visiting an element of an array or object
+ using VisitorCallback = AZStd::function;
+
+ //! Invokes the visitor callback for each element of either the array or object at @path
+ //! If @path is not an array or object, then no elements are visited
+ //! This function will not recurse into children of elements
+ //! @visitCallback functor that is invoked for each array or object element found
+ bool VisitField(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path);
+ //! Invokes the visitor callback for each element of the array at @path
+ //! If @path is not an array, then no elements are visited
+ //! This function will not recurse into children of elements
+ //! @visitCallback functor that is invoked for each array element found
+ bool VisitArray(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path);
+ //! Invokes the visitor callback for each element of the object at @path
+ //! If @path is not an object, then no elements are visited
+ //! This function will not recurse into children of elements
+ //! @visitCallback functor that is invoked for each object element found
+ bool VisitObject(AZ::SettingsRegistryInterface& settingsRegistry, const VisitorCallback& visitCallback, AZStd::string_view path);
+}
diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake
index 010c748402..6675958247 100644
--- a/Code/Framework/AzCore/AzCore/azcore_files.cmake
+++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake
@@ -566,6 +566,8 @@ set(FILES
Settings/SettingsRegistryMergeUtils.h
Settings/SettingsRegistryScriptUtils.cpp
Settings/SettingsRegistryScriptUtils.h
+ Settings/SettingsRegistryVisitorUtils.cpp
+ Settings/SettingsRegistryVisitorUtils.h
State/HSM.cpp
State/HSM.h
Statistics/NamedRunningStatistic.h
diff --git a/Code/Framework/AzCore/AzCore/std/math.h b/Code/Framework/AzCore/AzCore/std/math.h
index 03f12e6e08..042dcca657 100644
--- a/Code/Framework/AzCore/AzCore/std/math.h
+++ b/Code/Framework/AzCore/AzCore/std/math.h
@@ -30,4 +30,49 @@ namespace AZStd
using std::sqrt;
using std::tan;
using std::trunc;
+
+} // namespace AZStd
+
+// from c++20 standard
+namespace AZStd::Internal
+{
+ template
+ constexpr T lerp(T a, T b, T t) noexcept
+ {
+ if ((a <= 0 && b >= 0) || (a >= 0 && b <= 0))
+ {
+ return t * b + (1 - t) * a;
+ }
+ if (t == 1)
+ {
+ return b;
+ }
+ const T x = a + t * (b - a);
+ if ((t > 1) == (b > a))
+ {
+ return b < x ? x : b;
+ }
+ else
+ {
+ return x < b ? x : b;
+ }
+ }
+} // namespace AZStd::Internal
+
+namespace AZStd
+{
+ constexpr float lerp(float a, float b, float t) noexcept
+ {
+ return Internal::lerp(a, b, t);
+ }
+
+ constexpr double lerp(double a, double b, double t) noexcept
+ {
+ return Internal::lerp(a, b, t);
+ }
+
+ constexpr long double lerp(long double a, long double b, long double t) noexcept
+ {
+ return Internal::lerp(a, b, t);
+ }
} // namespace AZStd
diff --git a/Code/Framework/AzCore/Tests/AZStd/Math.cpp b/Code/Framework/AzCore/Tests/AZStd/Math.cpp
new file mode 100644
index 0000000000..5379c9946b
--- /dev/null
+++ b/Code/Framework/AzCore/Tests/AZStd/Math.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+namespace UnitTest
+{
+ template
+ class StdMathTest : public ::testing::Test
+ {
+ };
+
+ using MathTestConfigs = ::testing::Types;
+ TYPED_TEST_CASE(StdMathTest, MathTestConfigs);
+
+ TYPED_TEST(StdMathTest, LerpOperations)
+ {
+ using AZStd::lerp;
+ using ::testing::Eq;
+ using T = TypeParam;
+
+ constexpr T maxNumber = AZStd::numeric_limits::max();
+ constexpr T eps = AZStd::numeric_limits::epsilon();
+ constexpr T a{ 42 };
+
+ // exactness: lerp(a,b,0)==a && lerp(a,b,1)==b
+ EXPECT_THAT(lerp(eps, maxNumber, T(0)), Eq(eps));
+ EXPECT_THAT(lerp(eps, maxNumber, T(1)), Eq(maxNumber));
+
+ // consistency: lerp(a,a,t)==a
+ EXPECT_THAT(lerp(a, a, T(0.5)), Eq(a));
+ EXPECT_THAT(lerp(eps, eps, T(0.5)), Eq(eps));
+
+ // a few generic tests taken from MathUtilTests.cpp
+ EXPECT_EQ(T(2.5), lerp(T(2), T(4), T(0.25)));
+ EXPECT_EQ(T(6.0), lerp(T(2), T(4), T(2.0)));
+ EXPECT_EQ(T(3.5), lerp(T(2), T(4), T(0.75)));
+ EXPECT_EQ(T(0.0), lerp(T(2), T(4), T(-1.0)));
+ }
+} // namespace UnitTest
diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryMergeUtilsTests.cpp
similarity index 100%
rename from Code/Framework/AzCore/Tests/SettingsRegistryMergeUtilsTests.cpp
rename to Code/Framework/AzCore/Tests/Settings/SettingsRegistryMergeUtilsTests.cpp
diff --git a/Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryTests.cpp
similarity index 100%
rename from Code/Framework/AzCore/Tests/SettingsRegistryTests.cpp
rename to Code/Framework/AzCore/Tests/Settings/SettingsRegistryTests.cpp
diff --git a/Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp
new file mode 100644
index 0000000000..15f346ee93
--- /dev/null
+++ b/Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace SettingsRegistryVisitorUtilsTests
+{
+ struct VisitCallbackParams
+ {
+ AZStd::string_view m_inputJsonDocument;
+ using VisitFieldFunction = bool(*)(AZ::SettingsRegistryInterface&,
+ const AZ::SettingsRegistryVisitorUtils::VisitorCallback&,
+ AZStd::string_view);
+
+ static inline constexpr size_t MaxFieldCount = 10;
+ using ObjectFields = AZStd::fixed_vector, MaxFieldCount>;
+ using ArrayFields = AZStd::fixed_vector;
+ ObjectFields m_objectFields;
+ ArrayFields m_arrayFields;
+ };
+
+ template
+ class SettingsRegistryVisitorUtilsParamFixture
+ : public UnitTest::ScopedAllocatorSetupFixture
+ , public ::testing::WithParamInterface
+ {
+ public:
+
+ void SetUp() override
+ {
+ m_registry = AZStd::make_unique();
+ }
+
+ void TearDown() override
+ {
+ m_registry.reset();
+ }
+
+ AZStd::unique_ptr m_registry;
+ };
+
+ using SettingsRegistryVisitCallbackFixture = SettingsRegistryVisitorUtilsParamFixture;
+
+ TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitFieldsOfArrayType_ReturnsFields)
+ {
+ const VisitCallbackParams& visitParams = GetParam();
+
+ ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch));
+
+ AZStd::fixed_vector testArrayFields;
+ auto visitorCallback = [this, &testArrayFields](AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type)
+ {
+ AZStd::string fieldValue;
+ EXPECT_TRUE(m_registry->Get(fieldValue, path));
+ testArrayFields.emplace_back(AZStd::move(fieldValue));
+ };
+
+ AZ::SettingsRegistryVisitorUtils::VisitField(*m_registry, visitorCallback, "/Test/Array");
+
+ const AZStd::fixed_vector expectedFields{
+ visitParams.m_arrayFields.begin(), visitParams.m_arrayFields.end() };
+ EXPECT_THAT(testArrayFields, ::testing::ContainerEq(expectedFields));
+ }
+
+ TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitFieldsOfObjectType_ReturnsFields)
+ {
+ const VisitCallbackParams& visitParams = GetParam();
+
+ ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch));
+
+ AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> testObjectFields;
+ auto visitorCallback = [this, &testObjectFields](AZStd::string_view path, AZStd::string_view fieldName, AZ::SettingsRegistryInterface::Type)
+ {
+ AZStd::string fieldValue;
+ EXPECT_TRUE(m_registry->Get(fieldValue, path));
+ testObjectFields.emplace_back(fieldName, AZStd::move(fieldValue));
+ };
+
+ AZ::SettingsRegistryVisitorUtils::VisitField(*m_registry, visitorCallback, "/Test/Object");
+
+ const AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> expectedFields{
+ visitParams.m_objectFields.begin(), visitParams.m_objectFields.end() };
+ EXPECT_THAT(testObjectFields, ::testing::ContainerEq(expectedFields));
+ }
+
+ TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitArrayOfArrayType_ReturnsFields)
+ {
+ const VisitCallbackParams& visitParams = GetParam();
+
+ ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch));
+
+ AZStd::fixed_vector testArrayFields;
+ auto visitorCallback = [this, &testArrayFields](AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type)
+ {
+ AZStd::string fieldValue;
+ EXPECT_TRUE(m_registry->Get(fieldValue, path));
+ testArrayFields.emplace_back(AZStd::move(fieldValue));
+ };
+
+ AZ::SettingsRegistryVisitorUtils::VisitArray(*m_registry, visitorCallback, "/Test/Array");
+
+ const AZStd::fixed_vector expectedArrayFields{
+ visitParams.m_arrayFields.begin(), visitParams.m_arrayFields.end() };
+ EXPECT_THAT(testArrayFields, ::testing::ContainerEq(expectedArrayFields));
+ }
+
+ TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitArrayOfObjectType_ReturnsEmpty)
+ {
+ const VisitCallbackParams& visitParams = GetParam();
+
+ ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch));
+
+ AZStd::fixed_vector testArrayFields;
+ auto visitorCallback = [this, &testArrayFields](AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type)
+ {
+ AZStd::string fieldValue;
+ EXPECT_TRUE(m_registry->Get(fieldValue, path));
+ testArrayFields.emplace_back(AZStd::move(fieldValue));
+ };
+
+ AZ::SettingsRegistryVisitorUtils::VisitArray(*m_registry, visitorCallback, "/Test/Object");
+
+ EXPECT_TRUE(testArrayFields.empty());
+ }
+
+ TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitObjectOfArrayType_ReturnsEmpty)
+ {
+ const VisitCallbackParams& visitParams = GetParam();
+
+ ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch));
+
+ AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> testObjectFields;
+ auto visitorCallback = [this, &testObjectFields](AZStd::string_view path, AZStd::string_view fieldName, AZ::SettingsRegistryInterface::Type)
+ {
+ AZStd::string fieldValue;
+ EXPECT_TRUE(m_registry->Get(fieldValue, path));
+ testObjectFields.emplace_back(fieldName, AZStd::move(fieldValue));
+ };
+
+ AZ::SettingsRegistryVisitorUtils::VisitObject(*m_registry, visitorCallback, "/Test/Array");
+
+ EXPECT_TRUE(testObjectFields.empty());
+ }
+
+ TEST_P(SettingsRegistryVisitCallbackFixture, VisitFunction_VisitObjectOfObjectType_ReturnsFields)
+ {
+ const VisitCallbackParams& visitParams = GetParam();
+
+ ASSERT_TRUE(m_registry->MergeSettings(visitParams.m_inputJsonDocument, AZ::SettingsRegistryInterface::Format::JsonMergePatch));
+
+ AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> testObjectFields;
+ auto visitorCallback = [this, &testObjectFields](AZStd::string_view path, AZStd::string_view fieldName, AZ::SettingsRegistryInterface::Type)
+ {
+ AZStd::string fieldValue;
+ EXPECT_TRUE(m_registry->Get(fieldValue, path));
+ testObjectFields.emplace_back(fieldName, AZStd::move(fieldValue));
+ };
+
+ AZ::SettingsRegistryVisitorUtils::VisitObject(*m_registry, visitorCallback, "/Test/Object");
+
+ const AZStd::fixed_vector, VisitCallbackParams::MaxFieldCount> expectedObjectFields{
+ visitParams.m_objectFields.begin(), visitParams.m_objectFields.end() };
+ EXPECT_THAT(testObjectFields, ::testing::ContainerEq(expectedObjectFields));
+ }
+
+
+ INSTANTIATE_TEST_CASE_P(
+ VisitField,
+ SettingsRegistryVisitCallbackFixture,
+ ::testing::Values(
+ VisitCallbackParams
+ {
+ R"({)" "\n"
+ R"( "Test":)" "\n"
+ R"( {)" "\n"
+ R"( "Array": [ "Hello", "World" ],)" "\n"
+ R"( "Object": { "Foo": "Hello", "Bar": "World"})" "\n"
+ R"( })" "\n"
+ R"(})" "\n",
+ VisitCallbackParams::ObjectFields{{"Foo", "Hello"}, {"Bar", "World"}},
+ VisitCallbackParams::ArrayFields{"Hello", "World"}
+ }
+ )
+ );
+}
diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake
index e155594aa0..6ba9944f7d 100644
--- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake
+++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake
@@ -75,11 +75,12 @@ set(FILES
Name/NameJsonSerializerTests.cpp
Name/NameTests.cpp
RTTI/TypeSafeIntegralTests.cpp
- SettingsRegistryTests.cpp
- SettingsRegistryMergeUtilsTests.cpp
Settings/CommandLineTests.cpp
+ Settings/SettingsRegistryTests.cpp
Settings/SettingsRegistryConsoleUtilsTests.cpp
+ Settings/SettingsRegistryMergeUtilsTests.cpp
Settings/SettingsRegistryScriptUtilsTests.cpp
+ Settings/SettingsRegistryVisitorUtilsTests.cpp
Streamer/BlockCacheTests.cpp
Streamer/DedicatedCacheTests.cpp
Streamer/FullDecompressorTests.cpp
@@ -194,6 +195,7 @@ set(FILES
AZStd/LockFreeQueues.cpp
AZStd/LockFreeStacks.cpp
AZStd/LockTests.cpp
+ AZStd/Math.cpp
AZStd/Numeric.cpp
AZStd/Ordered.cpp
AZStd/Optional.cpp
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp
index d9451949ea..d2144457c8 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/CardNotification.cpp
@@ -33,6 +33,9 @@ namespace AzQtComponents
titleLabel->setObjectName("Title");
titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
titleLabel->setWordWrap(true);
+ titleLabel->setTextFormat(Qt::RichText);
+ titleLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ titleLabel->setOpenExternalLinks(true);
QHBoxLayout* headerLayout = new QHBoxLayout(headerFrame);
headerLayout->setSizeConstraint(QLayout::SetMinimumSize);
diff --git a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp
index a82c4a6914..b2b67c3b75 100644
--- a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp
+++ b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp
@@ -22,22 +22,33 @@
#include
#include
#include
+#include
#include
#include
namespace LegacyLevelSystem
{
+ constexpr AZStd::string_view DeferredLoadLevelKey = "/O3DE/Runtime/SpawnableLevelSystem/DeferredLoadLevel";
//------------------------------------------------------------------------
static void LoadLevel(const AZ::ConsoleCommandContainer& arguments)
{
AZ_Error("SpawnableLevelSystem", !arguments.empty(), "LoadLevel requires a level file name to be provided.");
AZ_Error("SpawnableLevelSystem", arguments.size() == 1, "LoadLevel requires a single level file name to be provided.");
- if (!arguments.empty() && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor())
+ if (!arguments.empty() && gEnv && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor())
{
gEnv->pSystem->GetILevelSystem()->LoadLevel(arguments[0].data());
}
+ else if (!arguments.empty())
+ {
+ // The SpawnableLevelSystem isn't available yet.
+ // Defer the level load until later by storing it in the SettingsRegistry
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ settingsRegistry->Set(DeferredLoadLevelKey, arguments.front());
+ }
+ }
}
//------------------------------------------------------------------------
@@ -45,7 +56,7 @@ namespace LegacyLevelSystem
{
AZ_Warning("SpawnableLevelSystem", !arguments.empty(), "UnloadLevel doesn't use any arguments.");
- if (gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor())
+ if (gEnv && gEnv->pSystem && gEnv->pSystem->GetILevelSystem() && !gEnv->IsEditor())
{
gEnv->pSystem->GetILevelSystem()->UnloadLevel();
}
@@ -73,6 +84,24 @@ namespace LegacyLevelSystem
}
AzFramework::RootSpawnableNotificationBus::Handler::BusConnect();
+
+ // If there were LoadLevel command invocations before the creation of the level system
+ // then those invocations were queued.
+ // load the last level in the queue, since only one level can be loaded at a time
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ if (AZ::SettingsRegistryInterface::FixedValueString deferredLevelName;
+ settingsRegistry->Get(deferredLevelName, DeferredLoadLevelKey) && !deferredLevelName.empty())
+ {
+ // since this is the constructor any derived classes vtables aren't setup yet
+ // call this class LoadLevel function
+ AZ_TracePrintf("SpawnableLevelSystem", "The Level System is now available."
+ " Loading level %s which could not be loaded earlier\n", deferredLevelName.c_str());
+ SpawnableLevelSystem::LoadLevel(deferredLevelName.c_str());
+ // Delete the key with the deferred level name
+ settingsRegistry->Remove(DeferredLoadLevelKey);
+ }
+ }
}
//------------------------------------------------------------------------
@@ -173,7 +202,7 @@ namespace LegacyLevelSystem
}
// Make sure a spawnable level exists that matches levelname
- AZStd::string validLevelName = "";
+ AZStd::string validLevelName;
AZ::Data::AssetId rootSpawnableAssetId;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
rootSpawnableAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, levelName, nullptr, false);
diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp
index 7c07ca207c..f8d0adf156 100644
--- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp
+++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -791,6 +792,7 @@ namespace PhysX
if (shapes.empty())
{
m_componentWarnings.clear();
+
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree);
return;
@@ -824,9 +826,16 @@ namespace PhysX
}
m_componentWarnings.push_back(AZStd::string::format(
- "The Physics Asset \"%s\" is a Triangle Mesh, it is not compatible with a Dynamic Rigidbody, either:\n"
- "Change the PhysicsAsset to Convex Mesh or set the Rigidbody to kinematic.",
+ "The physics asset \"%s\" was exported using triangle mesh geometry, which is not compatible with non-kinematic "
+ "dynamic rigid bodies. To make the collider compatible, you can export the asset using primitive or convex mesh "
+ "geometry, use mesh decomposition when exporting the asset, or set the rigid body to kinematic. Learn more about "
+ "colliders.",
assetPath.c_str()));
+
+ // make sure the entity inspector scrolls so the warning is visible by marking this component as having
+ // new content
+ AzToolsFramework::EntityPropertyEditorRequestBus::Broadcast(
+ &AzToolsFramework::EntityPropertyEditorRequests::SetNewComponentId, GetId());
}
else
{
@@ -839,8 +848,8 @@ namespace PhysX
}
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
- &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree);
-
+ &AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay,
+ m_componentWarnings.empty() ? AzToolsFramework::Refresh_EntireTree : AzToolsFramework::Refresh_EntireTree_NewContent);
}
void EditorColliderComponent::OnAssetReloaded(AZ::Data::Asset asset)
diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp
index 447c2755c6..24b2586c9e 100644
--- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp
+++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp
@@ -103,7 +103,6 @@ namespace PhysX
}
} // namespace Internal
-
void EditorRigidBodyConfiguration::Reflect(AZ::ReflectContext* context)
{
auto serializeContext = azrtti_cast(context);
@@ -310,6 +309,15 @@ namespace PhysX
}
}
+ void EditorRigidBodyComponent::OnConfigurationChanged()
+ {
+ CreateEditorWorldRigidBody();
+
+ // required in case the kinematic setting has changed
+ PhysX::EditorColliderValidationRequestBus::Event(
+ GetEntityId(), &PhysX::EditorColliderValidationRequestBus::Events::ValidateRigidBodyMeshGeometryType);
+ }
+
void EditorRigidBodyComponent::Reflect(AZ::ReflectContext* context)
{
EditorRigidBodyConfiguration::Reflect(context);
@@ -336,7 +344,7 @@ namespace PhysX
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/physx/rigid-body-physics/")
->DataElement(0, &EditorRigidBodyComponent::m_config, "Configuration", "Configuration for rigid body physics.")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
- ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorRigidBodyComponent::CreateEditorWorldRigidBody)
+ ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorRigidBodyComponent::OnConfigurationChanged)
;
}
}
diff --git a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h
index 5d63ec9705..ed147ad8cb 100644
--- a/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h
+++ b/Gems/PhysX/Code/Source/EditorRigidBodyComponent.h
@@ -120,6 +120,8 @@ namespace PhysX
void InitPhysicsTickHandler();
void PrePhysicsTick();
+ void OnConfigurationChanged();
+
Debug::DebugDisplayDataChangedEvent::Handler m_debugDisplayDataChangeHandler;
EditorRigidBodyConfiguration m_config;
diff --git a/Registry/setregbuilder.assetprocessor.setreg b/Registry/setregbuilder.assetprocessor.setreg
index 25b51470bf..00e6e2f7f8 100644
--- a/Registry/setregbuilder.assetprocessor.setreg
+++ b/Registry/setregbuilder.assetprocessor.setreg
@@ -20,7 +20,8 @@
"Excludes":
[
"/Amazon/AzCore/Runtime",
- "/Amazon/AzCore/Bootstrap/project_path"
+ "/Amazon/AzCore/Bootstrap/project_path",
+ "/O3DE/Runtime",
]
}
}
diff --git a/scripts/build/bootstrap/incremental_build_util.py b/scripts/build/bootstrap/incremental_build_util.py
index 101e31b5db..5c77559085 100644
--- a/scripts/build/bootstrap/incremental_build_util.py
+++ b/scripts/build/bootstrap/incremental_build_util.py
@@ -18,6 +18,8 @@ from contextlib import contextmanager
import threading
import _thread
+from botocore.config import Config
+
DEFAULT_REGION = 'us-west-2'
DEFAULT_DISK_SIZE = 300
DEFAULT_DISK_TYPE = 'gp2'
@@ -173,10 +175,27 @@ def get_region_name():
def get_ec2_client(region):
- client = boto3.client('ec2', region_name=region)
+ client_config = Config(
+ region_name=region,
+ retries={
+ 'mode': 'standard'
+ }
+ )
+ client = boto3.client('ec2', config=client_config)
return client
+def get_ec2_resource(region):
+ resource_config = Config(
+ region_name=region,
+ retries={
+ 'mode': 'standard'
+ }
+ )
+ resource = boto3.resource('ec2', config=resource_config)
+ return resource
+
+
def get_ec2_instance_id():
try:
instance_id = urllib.request.urlopen('http://169.254.169.254/latest/meta-data/instance-id').read()
@@ -395,14 +414,11 @@ def detach_volume_from_ec2_instance(volume, ec2_instance_id, force, timeout_dura
def mount_ebs(snapshot_hint, repository_name, project, pipeline, branch, platform, build_type, disk_size, disk_type):
- session = boto3.session.Session()
- region = session.region_name
- if region is None:
- region = DEFAULT_REGION
+ region = get_region_name()
ec2_client = get_ec2_client(region)
ec2_instance_id = get_ec2_instance_id()
ec2_availability_zone = get_availability_zone()
- ec2_resource = boto3.resource('ec2', region_name=region)
+ ec2_resource = get_ec2_resource(region)
ec2_instance = ec2_resource.Instance(ec2_instance_id)
for volume in ec2_instance.volumes.all():
@@ -469,7 +485,7 @@ def mount_ebs(snapshot_hint, repository_name, project, pipeline, branch, platfor
def unmount_ebs():
region = get_region_name()
ec2_instance_id = get_ec2_instance_id()
- ec2_resource = boto3.resource('ec2', region_name=region)
+ ec2_resource = get_ec2_resource(region)
ec2_instance = ec2_resource.Instance(ec2_instance_id)
if os.path.isfile('envinject.properties'):