From c562f0a80719b7ddc73544d5f6fd0cd03d5a23f8 Mon Sep 17 00:00:00 2001 From: greerdv Date: Fri, 8 Oct 2021 16:56:53 +0100 Subject: [PATCH 01/10] small improvements to triangle mesh rigid body warning Signed-off-by: greerdv --- .../Components/Widgets/CardNotification.cpp | 3 +++ .../Code/Source/EditorColliderComponent.cpp | 17 +++++++++++++---- .../Code/Source/EditorRigidBodyComponent.cpp | 12 ++++++++++-- .../Code/Source/EditorRigidBodyComponent.h | 2 ++ 4 files changed, 28 insertions(+), 6 deletions(-) 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/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 7c07ca207c..7cc69caeb7 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 asset \"%s\" contains one or more triangle meshes, which are not compatible with non-kinematic dynamic " + "rigid bodies. To make the collider compatible, you can export the asset as a primitive or convex mesh, 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; From e256df3f05c778d7ddad16471b18aa87fb504a54 Mon Sep 17 00:00:00 2001 From: brianherrera Date: Fri, 8 Oct 2021 10:05:50 -0700 Subject: [PATCH 02/10] Add retry config to boto3 clients This change makes the inc_build_util script more resilient against transient network issues and issues encountered during node boot-up. Signed-off-by: brianherrera --- .../build/bootstrap/incremental_build_util.py | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) 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'): From de41653d26e87eed74f1d8d71009a2d44715b40c Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Fri, 8 Oct 2021 13:36:46 -0700 Subject: [PATCH 03/10] remove LY_PROJECTS check in Atom test registrations so that the targets build in project centric builds (#4581) Signed-off-by: jromnoa --- AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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 From cef41261004e1b76171882115a38be4872e4b7fe Mon Sep 17 00:00:00 2001 From: smurly Date: Fri, 8 Oct 2021 13:49:51 -0700 Subject: [PATCH 04/10] Mesh component parallel test automation P0 (#4562) * Mesh component P0 automation for parallel testing Signed-off-by: Scott Murray * Remove unused imports Signed-off-by: Scott Murray * Decorating test classes with test_case_id to corresponding testrail cases Signed-off-by: Scott Murray --- .../Atom/TestSuite_Main_Optimized.py | 14 ++ .../hydra_AtomEditorComponents_MeshAdded.py | 171 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py 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) From d3f6898ad6e617d5f40e7f45bc7098a1ce098569 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Fri, 8 Oct 2021 15:01:20 -0700 Subject: [PATCH 05/10] Fixes test_MaterialEditorLaunch_AllRHIOptionsSucceed() test by searching for RHI log lines (#4511) * double test timeout from 60 seconds to 120 seconds in attempt to fix it for nightly GPU runs Signed-off-by: jromnoa * add a file to launch with the test to ensure we get a full viewport load completed Signed-off-by: jromnoa * fix import error Signed-off-by: jromnoa * remove python error checks Signed-off-by: jromnoa * add new log line specific to each RHI to check for Signed-off-by: jromnoa * remove the new test script as it is no longer needed with our improved log lines check - the viewport logs don't show up in AR for some reason Signed-off-by: jromnoa --- .../Gem/PythonTests/Atom/TestSuite_Main_GPU.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) 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], From e4d3ab118c02071d5533ea90525cb8b43589ea62 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 8 Oct 2021 17:59:57 -0500 Subject: [PATCH 06/10] Console changes: Added a new SettingsRegistry root key for executing (#4567) console commands. The new key is "/O3DE/Autoexec/ConsoleCommands" and the only difference with the "/Amazon/AzCore/Runtime/ConosleCommands" key is that it isn't excluded by the SettingsRegistryBuilder. Due to not being excluded by the SettingsRegistryBuilder this key can be used to forward console commands to the aggregate `bootstrap.game...setreg` files. For GameLauncher specific console commands it is recommend to be put them in .setreg file that uses the "game" specialization, such as "autoexec.game.setreg". Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Console/Console.cpp | 32 +++++++++++++------ .../AzCore/AzCore/Console/IConsole.h | 3 +- 2 files changed, 25 insertions(+), 10 deletions(-) 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; From 7b1dd01d1d648b2e449dba283d051bcae2414483 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 8 Oct 2021 20:09:22 -0500 Subject: [PATCH 07/10] Implemented a deferred LoadLevel queue for the SpawnableLevelSystem (#4561) * Moved the SettingsRegistryTests.cpp and SettingsRegistryMergeUtilsTests.cpp to the Settings folder Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Implemented a deferred level load queue, that allows the SpawnableLevelSystem to re-run the last LoadLevel command that occured before it was constructed. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added SettingsRegistryVisitorUtils to reduce Array and Object visitor boilerplate. The VisitArray and VisitObject functions allows iteration over each element of array and object respectively via a callback. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed the queuing logic for levels that attempt to load before the SpawnableLevelSystem is available Only the last level name that could not load is stored off and deferred until the SpawnableLevelsystem is created. Made the FieldVisitor AggregateTypes constructor protected and added a comment specifying the expected values. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Bring in the SettingsRegistry::Visitor::Visit functions into scope to fix MSVC compilation errors. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed the list of supported SettingsRegistry types to visit to an enum to constrain the values to Array and/or Object. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/AzCore/Settings/SettingsRegistry.h | 4 +- .../Settings/SettingsRegistryVisitorUtils.cpp | 136 ++++++++++++ .../Settings/SettingsRegistryVisitorUtils.h | 83 ++++++++ .../AzCore/AzCore/azcore_files.cmake | 2 + .../SettingsRegistryMergeUtilsTests.cpp | 0 .../{ => Settings}/SettingsRegistryTests.cpp | 0 .../SettingsRegistryVisitorUtilsTests.cpp | 196 ++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 5 +- .../LevelSystem/SpawnableLevelSystem.cpp | 35 +++- Registry/setregbuilder.assetprocessor.setreg | 3 +- 10 files changed, 456 insertions(+), 8 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.cpp create mode 100644 Code/Framework/AzCore/AzCore/Settings/SettingsRegistryVisitorUtils.h rename Code/Framework/AzCore/Tests/{ => Settings}/SettingsRegistryMergeUtilsTests.cpp (100%) rename Code/Framework/AzCore/Tests/{ => Settings}/SettingsRegistryTests.cpp (100%) create mode 100644 Code/Framework/AzCore/Tests/Settings/SettingsRegistryVisitorUtilsTests.cpp 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/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..d738711a4f 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 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/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", ] } } From c3ff1e0cd3e6a3c9145a9972d2090d802d8bdba2 Mon Sep 17 00:00:00 2001 From: greerdv Date: Mon, 11 Oct 2021 11:15:55 +0100 Subject: [PATCH 08/10] feedback from PR Signed-off-by: greerdv --- Gems/PhysX/Code/Source/EditorColliderComponent.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp index 7cc69caeb7..f8d0adf156 100644 --- a/Gems/PhysX/Code/Source/EditorColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorColliderComponent.cpp @@ -826,9 +826,9 @@ namespace PhysX } m_componentWarnings.push_back(AZStd::string::format( - "The asset \"%s\" contains one or more triangle meshes, which are not compatible with non-kinematic dynamic " - "rigid bodies. To make the collider compatible, you can export the asset as a primitive or convex mesh, use mesh " - "decomposition when exporting the asset, or set the rigid body to kinematic. Learn more about " + "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())); From b91d503a824a18b14ad8e724cd11cb805aec7e44 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Mon, 11 Oct 2021 12:55:24 +0200 Subject: [PATCH 09/10] Add AZStd::lerp math function, based on C++20 (#3468) * Add AZStd::lerp math function, based on c++20 Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Add unit test for AZStd::lerp, based on libc++ ones Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * written a reduced set of lerp tests, but now the license is correct Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Update Code/Framework/AzCore/AzCore/std/math.h Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Update Code/Framework/AzCore/Tests/AZStd/Math.cpp Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix the github suggestion merge Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Copy some AZ::Lerp tests to std::lerp test suite + clang-format Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Cleanup lerp test cases Remove comments that suggested very heavy tests that required things like `for every t1..` Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix unit test compilation issues Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix whitespace issue Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Use `TypeParam` in TYPED_TEST Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove unneeded new-lines Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * remove unused infinity Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/std/math.h | 45 ++++++++++++++++++ Code/Framework/AzCore/Tests/AZStd/Math.cpp | 46 +++++++++++++++++++ .../AzCore/Tests/azcoretests_files.cmake | 1 + 3 files changed, 92 insertions(+) create mode 100644 Code/Framework/AzCore/Tests/AZStd/Math.cpp 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/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index d738711a4f..6ba9944f7d 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -195,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 From f84bd9829a82e2b131ae913fcf134cc35fe32ad3 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Mon, 11 Oct 2021 13:01:14 +0100 Subject: [PATCH 10/10] remove some flackyness in physx automated tests (#4547) Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../PythonTests/Physics/TestSuite_Periodic.py | 4 - ...egion_SplineRegionWithModifiedTransform.py | 2 +- .../ForceRegion_ZeroPointForceDoesNothing.py | 2 +- .../Physics/tests/joints/JointsHelper.py | 11 +- .../joints/Joints_FixedLeadFollowerCollide.py | 92 ----- .../RigidBody_KinematicModeWorks.py | 30 +- .../Joints_FixedLeadFollowerCollide.ly | 3 - .../filelist.xml | 6 - .../Joints_FixedLeadFollowerCollide/level.pak | 3 - .../leveldata/Environment.xml | 14 - .../leveldata/TerrainTexture.xml | 7 - .../leveldata/TimeOfDay.xml | 356 ------------------ .../leveldata/VegetationMap.dat | 3 - .../Joints_FixedLeadFollowerCollide/tags.txt | 12 - .../terraintexture.pak | 3 - .../Joints_HingeNoLimitsConstrained.ly | 4 +- .../RigidBody_KinematicModeWorks.ly | 4 +- 17 files changed, 30 insertions(+), 526 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/Physics/tests/joints/Joints_FixedLeadFollowerCollide.py delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/Joints_FixedLeadFollowerCollide.ly delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/filelist.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/level.pak delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/Environment.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TerrainTexture.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/TimeOfDay.xml delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/leveldata/VegetationMap.dat delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/tags.txt delete mode 100644 AutomatedTesting/Levels/Physics/Joints_FixedLeadFollowerCollide/terraintexture.pak 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