diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index 043485d869..f133780fbc 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -130,8 +130,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::LandscapeCanvasTests_Main TEST_SERIAL TEST_SUITE main - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas - PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark" + PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/test_LandscapeCanvas_Main.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor @@ -144,8 +143,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::LandscapeCanvasTests_Periodic TEST_SERIAL TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas - PYTEST_MARKS "SUITE_periodic" + PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/test_LandscapeCanvas_Periodic.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor @@ -159,7 +157,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::GradientSignalTests_Periodic TEST_SERIAL TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal + PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/test_GradientSignal_Periodic.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py index beb5c2af72..2052c59a94 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py @@ -10,6 +10,7 @@ import sys sys.path.append(os.path.dirname(os.path.abspath(__file__))) import azlmbr.asset as asset +import azlmbr.editor as editor import azlmbr.legacy.general as general import azlmbr.bus as bus import azlmbr.math as math @@ -107,7 +108,7 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper): # Create an entity with a PhysX Collider and our PhysX Collider Surface Tag Emitter collider_entity = hydra.Entity("Collider Surface") collider_entity.create_entity( - entity_center_point, + entity_center_point, ["PhysX Collider", "PhysX Collider Surface Tag Emitter"] ) if collider_entity.id.IsValid(): @@ -153,23 +154,29 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper): self.test_success = self.test_success and baseline_success # Setup collider entity with a PhysX Mesh - test_physx_mesh_asset_path = asset.AssetCatalogRequestBus( + test_physx_mesh_asset_id = asset.AssetCatalogRequestBus( bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics", "c4044697_material_perfacematerialvalidation", "test.pxmesh"), math.Uuid(), False) - hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", 7) - hydra.get_set_test(collider_entity, 0, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_path) + + # Remove/re-add component due to LYN-5496 + collider_entity.remove_component("PhysX Collider") + collider_entity.add_component("PhysX Collider") + self.wait_for_condition(lambda: editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', + collider_entity.components[1]), 5.0) + hydra.get_set_test(collider_entity, 1, "Shape Configuration|Shape", 7) + hydra.get_set_test(collider_entity, 1, "Shape Configuration|Asset|PhysX Mesh", test_physx_mesh_asset_id) # Set the asset scale to match the test heights of the shapes tested asset_scale = math.Vector3(1.0, 1.0, 9.0) - collider_entity.get_set_test(0, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale) + collider_entity.get_set_test(1, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale) # Test: Generate a new surface on the collider. # There should be one instance at the very top of the collider mesh, and none on the baseline surface # (We use a small query box to only check for one placed instance point) self.log("Starting PhysX Mesh Collider Test") - hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [surface_tag]) - hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [invalid_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [surface_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [invalid_tag]) top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0) self.test_success = self.test_success and top_point_success baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point, @@ -180,8 +187,8 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper): # There should be no instances at the very top of the collider mesh, and none on the baseline surface within # our query box as PhysX meshes are treated as hollow shells, not solid volumes. # (We use a small query box to only check for one placed instance point) - hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [invalid_tag]) - hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [surface_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Generated Tags", [invalid_tag]) + hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [surface_tag]) top_point_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0) self.test_success = self.test_success and top_point_success baseline_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point, diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py index 37679d34ef..09cd760647 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py @@ -4,124 +4,118 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientGeneratorIncompatibilities(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientGeneratorIncompatibilities", args=["level"]) +def GradientGenerators_Incompatibilities(): + """ + Summary: + This test verifies that components are disabled when conflicting components are present on the same entity. - def run_test(self): - """ - Summary: - This test verifies that components are disabled when conflicting components are present on the same entity. + Expected Behavior: + Gradient Generator components are incompatible with Vegetation area components. - Expected Behavior: - Gradient Generator components are incompatible with Vegetation area components. + Test Steps: + 1) Open a simple level + 2) Create a new entity in the level + 3) Add each Gradient Generator component to an entity, and add a Vegetation Area component to the same entity + 4) Verify that components are only enabled when entity is free of a conflicting component - Test Steps: - 1) Create a new level - 2) Create a new entity in the level - 3) Add each Gradient Generator component to an entity, and add a Vegetation Area component to the same entity - 4) Verify that components are only enabled when entity is free of a conflicting component + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity - gradient_generators = [ - 'Altitude Gradient', - 'Constant Gradient', - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient', - 'Shape Falloff Gradient', - 'Slope Gradient', - 'Surface Mask Gradient' - ] - require_transform_modifiers = [ - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient' - ] - vegetation_areas = [ - 'Vegetation Layer Spawner', - 'Vegetation Layer Blender', - 'Vegetation Layer Blocker', - 'Vegetation Layer Blocker (Mesh)' - ] - area_dependencies = { - 'Vegetation Layer Spawner': 'Vegetation Asset List', - 'Vegetation Layer Blocker (Mesh)': 'Mesh' - } + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + gradient_generators = [ + 'Altitude Gradient', + 'Constant Gradient', + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient', + 'Shape Falloff Gradient', + 'Slope Gradient', + 'Surface Mask Gradient' + ] + require_transform_modifiers = [ + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient' + ] + vegetation_areas = [ + 'Vegetation Layer Spawner', + 'Vegetation Layer Blender', + 'Vegetation Layer Blocker', + 'Vegetation Layer Blocker (Mesh)' + ] + area_dependencies = { + 'Vegetation Layer Spawner': 'Vegetation Asset List', + 'Vegetation Layer Blocker (Mesh)': 'Mesh' + } - # For every gradient generator component, verify that they are incompatible - # which each vegetation area component - for component_name in gradient_generators: - for vegetation_area_name in vegetation_areas: - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Most of these need a shape, so use a Box Shape - hydra.add_component('Box Shape', entity_id) + # For every gradient generator component, verify that they are incompatible + # which each vegetation area component + for component_name in gradient_generators: + for vegetation_area_name in vegetation_areas: + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - # Add the specific vegetation area dependencies (if necessary) - if vegetation_area_name in area_dependencies: - hydra.add_component(area_dependencies[vegetation_area_name], entity_id) + # Most of these need a shape, so use a Box Shape + hydra.add_component('Box Shape', entity_id) - # Add the vegetation area component we are validating against, then add the - # gradient generator afterwards, so that the gradient generator will actually - # be disabled (if it was present before, it would only get deactivated instead of disabled - # by the vegetation area) - area_component = hydra.add_component(vegetation_area_name, entity_id) - gradient_component = hydra.add_component(component_name, entity_id) + # Add the specific vegetation area dependencies (if necessary) + if vegetation_area_name in area_dependencies: + hydra.add_component(area_dependencies[vegetation_area_name], entity_id) - # Verify the gradient generator component is disabled since the vegetation area is incompatible - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log(f"{component_name} is disabled before removing {vegetation_area_name} component") + # Add the vegetation area component we are validating against, then add the + # gradient generator afterwards, so that the gradient generator will actually + # be disabled (if it was present before, it would only get deactivated instead of disabled + # by the vegetation area) + area_component = hydra.add_component(vegetation_area_name, entity_id) + gradient_component = hydra.add_component(component_name, entity_id) - # Remove the vegetation area component - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) + # Verify the gradient generator component is disabled since the vegetation area is incompatible + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_disabled = ( + f"{component_name} is disabled before removing {vegetation_area_name} component", + f"{component_name} is unexpectedly enabled before removing {vegetation_area_name} component" + ) + Report.result(component_is_disabled, not active) - # Add required dependencies for our gradient generators after the vegetation - # area has been removed, because the transform modifier is also incompatible - # with the vegetation areas - if component_name in require_transform_modifiers: - hydra.add_component('Gradient Transform Modifier', entity_id) + # Remove the vegetation area component + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) - # Verify the gradient generator component is enabled now that the vegetation area is gone - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and active - if active: - self.log(f"{component_name} is enabled after removing {vegetation_area_name} component") + # Add required dependencies for our gradient generators after the vegetation + # area has been removed, because the transform modifier is also incompatible + # with the vegetation areas + if component_name in require_transform_modifiers: + hydra.add_component('Gradient Transform Modifier', entity_id) + + # Verify the gradient generator component is enabled now that the vegetation area is gone + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_enabled = ( + f"{component_name} is enabled after removing {vegetation_area_name} component", + f"{component_name} is unexpectedly disabled after removing {vegetation_area_name} component" + ) + Report.result(component_is_enabled, active) -test = TestGradientGeneratorIncompatibilities() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientGenerators_Incompatibilities) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py index 8908493187..a4d9181744 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py @@ -4,164 +4,162 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientModifiersIncompatibilities(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientModifiersIncompatibilities", args=["level"]) +def GradientModifiers_Incompatibilities(): + """ + Summary: + This test verifies that components are disabled when conflicting components are present on the same entity. - def run_test(self): - """ - Summary: - This test verifies that components are disabled when conflicting components are present on the same entity. + Expected Behavior: + Gradient Modifier components are incompatible with Vegetation area components. - Expected Behavior: - Gradient Modifier components are incompatible with Vegetation area components. + Test Steps: + 1) Open a simple level + 2) Create a new entity in the level + 3) Add each Gradient Modifier component to an entity, and add a Vegetation Area component to the same entity + 4) Verify that components are only enabled when entity is free of a conflicting component - Test Steps: - 1) Create a new level - 2) Create a new entity in the level - 3) Add each Gradient Modifier component to an entity, and add a Vegetation Area component to the same entity - 4) Verify that components are only enabled when entity is free of a conflicting component + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity - gradient_generators = [ - 'Altitude Gradient', - 'Constant Gradient', - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient', - 'Shape Falloff Gradient', - 'Slope Gradient', - 'Surface Mask Gradient' - ] - require_transform_modifiers = [ - 'FastNoise Gradient', - 'Image Gradient', - 'Perlin Noise Gradient', - 'Random Noise Gradient' - ] - gradient_modifiers = [ - 'Dither Gradient Modifier', - 'Gradient Mixer', - 'Invert Gradient Modifier', - 'Levels Gradient Modifier', - 'Posterize Gradient Modifier', - 'Smooth-Step Gradient Modifier', - 'Threshold Gradient Modifier' - ] - vegetation_areas = [ - 'Vegetation Layer Spawner', - 'Vegetation Layer Blender', - 'Vegetation Layer Blocker', - 'Vegetation Layer Blocker (Mesh)' - ] - area_dependencies = { - 'Vegetation Layer Spawner': 'Vegetation Asset List', - 'Vegetation Layer Blocker (Mesh)': 'Mesh' - } + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + gradient_generators = [ + 'Altitude Gradient', + 'Constant Gradient', + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient', + 'Shape Falloff Gradient', + 'Slope Gradient', + 'Surface Mask Gradient' + ] + require_transform_modifiers = [ + 'FastNoise Gradient', + 'Image Gradient', + 'Perlin Noise Gradient', + 'Random Noise Gradient' + ] + gradient_modifiers = [ + 'Dither Gradient Modifier', + 'Gradient Mixer', + 'Invert Gradient Modifier', + 'Levels Gradient Modifier', + 'Posterize Gradient Modifier', + 'Smooth-Step Gradient Modifier', + 'Threshold Gradient Modifier' + ] + vegetation_areas = [ + 'Vegetation Layer Spawner', + 'Vegetation Layer Blender', + 'Vegetation Layer Blocker', + 'Vegetation Layer Blocker (Mesh)' + ] + area_dependencies = { + 'Vegetation Layer Spawner': 'Vegetation Asset List', + 'Vegetation Layer Blocker (Mesh)': 'Mesh' + } - # For every gradient modifier component, verify that they are incompatible - # which each vegetation area and gradient generator/modifier component - all_gradients = gradient_modifiers + gradient_generators - for component_name in gradient_modifiers: - for vegetation_area_name in vegetation_areas: - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Most of these need a shape, so use a Box Shape - hydra.add_component('Box Shape', entity_id) + # For every gradient modifier component, verify that they are incompatible + # which each vegetation area and gradient generator/modifier component + all_gradients = gradient_modifiers + gradient_generators + for component_name in gradient_modifiers: + for vegetation_area_name in vegetation_areas: + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - # Add the specific vegetation area dependencies (if necessary) - if vegetation_area_name in area_dependencies: - hydra.add_component(area_dependencies[vegetation_area_name], entity_id) + # Most of these need a shape, so use a Box Shape + hydra.add_component('Box Shape', entity_id) - # Add the vegetation area component we are validating against, then add the - # gradient modifier afterwards, so that the gradient modifier will actually - # be disabled (if it was present before, it would only get deactivated instead of disabled - # by the vegetation area) - area_component = hydra.add_component(vegetation_area_name, entity_id) - gradient_component = hydra.add_component(component_name, entity_id) + # Add the specific vegetation area dependencies (if necessary) + if vegetation_area_name in area_dependencies: + hydra.add_component(area_dependencies[vegetation_area_name], entity_id) - # Verify the gradient modifier component is disabled since the vegetation area is incompatible - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log("{gradient} is disabled before removing {vegetation_area} component".format(gradient=component_name, vegetation_area=vegetation_area_name)) + # Add the vegetation area component we are validating against, then add the + # gradient modifier afterwards, so that the gradient modifier will actually + # be disabled (if it was present before, it would only get deactivated instead of disabled + # by the vegetation area) + area_component = hydra.add_component(vegetation_area_name, entity_id) + gradient_component = hydra.add_component(component_name, entity_id) - # Remove the vegetation area component - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) + # Verify the gradient modifier component is disabled since the vegetation area is incompatible + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_disabled = ( + f"{component_name} is disabled before removing {vegetation_area_name} component", + f"{component_name} is unexpectedly enabled before removing {vegetation_area_name} component" + ) + Report.result(component_is_disabled, not active) - # Verify the gradient modifier component is enabled now that the vegetation area is gone - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and active - if active: - self.log("{gradient} is enabled after removing {vegetation_area} component".format(gradient=component_name, vegetation_area=vegetation_area_name)) + # Remove the vegetation area component + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [area_component]) - for gradient_name in all_gradients: - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + # Verify the gradient modifier component is enabled now that the vegetation area is gone + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_enabled = ( + f"{component_name} is enabled after removing {vegetation_area_name} component", + f"{component_name} is unexpectedly disabled after removing {vegetation_area_name} component" + ) + Report.result(component_is_enabled, active) - # Most of these need a shape, so use a Box Shape - hydra.add_component('Box Shape', entity_id) + for gradient_name in all_gradients: + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - # Add the specific gradient generator dependencies (if necessary) - conflicting_components = [] - if gradient_name in require_transform_modifiers: - component = hydra.add_component('Gradient Transform Modifier', entity_id) - conflicting_components.append(component) + # Most of these need a shape, so use a Box Shape + hydra.add_component('Box Shape', entity_id) - # Add the gradient component we are validating against, then add the - # gradient modifier afterwards, so that the gradient modifier will actually - # be disabled (if it was present before, it would only get deactivated instead of disabled - # by the other gradient) - component = hydra.add_component(gradient_name, entity_id) + # Add the specific gradient generator dependencies (if necessary) + conflicting_components = [] + if gradient_name in require_transform_modifiers: + component = hydra.add_component('Gradient Transform Modifier', entity_id) conflicting_components.append(component) - gradient_component = hydra.add_component(component_name, entity_id) - # Verify the gradient modifier component is disabled since the other gradient is incompatible - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log("{gradient} is disabled before removing {conflicting_gradient} component".format(gradient=component_name, conflicting_gradient=gradient_name)) + # Add the gradient component we are validating against, then add the + # gradient modifier afterwards, so that the gradient modifier will actually + # be disabled (if it was present before, it would only get deactivated instead of disabled + # by the other gradient) + component = hydra.add_component(gradient_name, entity_id) + conflicting_components.append(component) + gradient_component = hydra.add_component(component_name, entity_id) - # Remove the conflicting gradient component (and transform modifier if it was added) - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', conflicting_components) + # Verify the gradient modifier component is disabled since the other gradient is incompatible + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_disabled = ( + f"{component_name} is disabled before removing {gradient_name} component", + f"{component_name} is unexpectedly enabled before removing {gradient_name} component" + ) + Report.result(component_is_disabled, not active) - # Verify the gradient modifier component is enabled now that the other gradient is gone - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) - self.test_success = self.test_success and active - if active: - self.log("{gradient} is enabled after removing {conflicting_gradient} component".format(gradient=component_name, conflicting_gradient=gradient_name)) + # Remove the conflicting gradient component (and transform modifier if it was added) + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', conflicting_components) + + # Verify the gradient modifier component is enabled now that the other gradient is gone + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_component) + component_is_enabled = ( + f"{component_name} is enabled after removing {gradient_name} component", + f"{component_name} is unexpectedly disabled after removing {gradient_name} component" + ) + Report.result(component_is_enabled, active) -test = TestGradientModifiersIncompatibilities() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientModifiers_Incompatibilities) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py index 73e8b95823..3749f93bf5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py @@ -5,129 +5,125 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths -import azlmbr.entity as EntityId +def GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(): + """ + Summary: + A temporary level is created. An entity for each test case is created and added with the corresponding + components to verify if the gradient transform is set to the world origin. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + 1) Preview image updates to reflect change in transform of the gradient sampler. + 2) New Preview Position property is exposed, and set to 0,0,0 (world origin). + 3) Preview Size is set to 1,1,1 by default. + Test Steps: + 1) Open level + 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity + 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity + 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity + 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity + 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity + 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity + 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity + 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity + 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity -class TestGradientPreviewSettings(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientPreviewSettings_ClearPinnedEntity", args=["level"]) + 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. - def run_test(self): - """ - Summary: - A temporary level is created. An entity for each test case is created and added with the corresponding - components to verify if the gradient transform is set to the world origin. + :return: None + """ - Expected Behavior: - 1) Preview image updates to reflect change in transform of the gradient sampler. - 2) New Preview Position property is exposed, and set to 0,0,0 (world origin). - 3) Preview Size is set to 1,1,1 by default. + import sys - Test Steps: - 1) Open level - 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity - 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity - 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity - 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity - 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity - 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity - 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity - 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity - 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - 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. + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - :return: None - """ + WORLD_ORIGIN = math.Vector3(0.0, 0.0, 0.0) + EXPECTED_SIZE = math.Vector3(1.0, 1.0, 1.0) + CLOSE_THRESHOLD = sys.float_info.min - WORLD_ORIGIN = math.Vector3(0.0, 0.0, 0.0) - EXPECTED_SIZE = math.Vector3(1.0, 1.0, 1.0) - CLOSE_THRESHOLD = sys.float_info.min + def create_entity(entity_name, components_to_add): + entity_position = math.Vector3(125.0, 136.0, 32.0) + entity_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + entity = hydra.Entity(entity_name, entity_id) + if entity_id.IsValid(): + print(f"{entity_name} entity Created") + entity.components = [] + for component in components_to_add: + entity.components.append(hydra.add_component(component, entity_id)) + return entity - def create_entity(enity_name, components_to_add): - entity_position = math.Vector3(125.0, 136.0, 32.0) - entity_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + def clear_entityid_check_position(entity_name, components_to_add, check_preview_size=False): + entity = create_entity(entity_name, components_to_add) + hydra.get_set_test(entity, 0, "Preview Settings|Pin Preview to Shape", EntityId.EntityId()) + preview_position = hydra.get_component_property_value( + entity.components[0], "Preview Settings|Preview Position" + ) + preview_set_to_origin = ( + f"{entity_name}: Preview Position set to world origin", + f"{entity_name}: Preview Position set to unexpected coords" + ) + Report.result(preview_set_to_origin, preview_position.IsClose(WORLD_ORIGIN, CLOSE_THRESHOLD)) + if check_preview_size: + preview_size = hydra.get_component_property_value(entity.components[0], "Preview Settings|Preview Size") + preview_size_default_set = ( + f"{entity_name}: Preview Size set as expected", + f"{entity_name}: Preview Size set to unexpected value. Expected {EXPECTED_SIZE}, Found {preview_size}" ) - entity = hydra.Entity(enity_name, entity_id) - if entity_id.IsValid(): - print(f"{enity_name} entity Created") - entity.components = [] - for component in components_to_add: - entity.components.append(hydra.add_component(component, entity_id)) - return entity + Report.result(preview_size_default_set, preview_size.IsClose(EXPECTED_SIZE, CLOSE_THRESHOLD)) + return entity - def clear_entityid_check_position(entity_name, components_to_add, check_preview_size=False): - entity = create_entity(entity_name, components_to_add) - hydra.get_set_test(entity, 0, "Preview Settings|Pin Preview to Shape", EntityId.EntityId()) - preview_position = hydra.get_component_property_value( - entity.components[0], "Preview Settings|Preview Position" - ) - if preview_position.IsClose(WORLD_ORIGIN, CLOSE_THRESHOLD): - print(f"{entity_name} --- Preview Position set to world origin") - if check_preview_size: - preview_size = hydra.get_component_property_value(entity.components[0], "Preview Settings|Preview Size") - if preview_size.IsClose(EXPECTED_SIZE, CLOSE_THRESHOLD): - print(f"{entity_name} --- Preview Size set to (1, 1, 1)") - return entity + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + # 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity + clear_entityid_check_position( + "Random Noise Gradient", ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True + ) - # 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity - clear_entityid_check_position( - "Random Noise Gradient", ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True - ) + # 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Levels Gradient Modifier", ["Levels Gradient Modifier"]) - # 3) Create entity with Levels Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Levels Gradient Modifier", ["Levels Gradient Modifier"]) + # 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Posterize Gradient Modifier", ["Posterize Gradient Modifier"]) - # 4) Create entity with Posterize Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Posterize Gradient Modifier", ["Posterize Gradient Modifier"]) + # 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Smooth-Step Gradient Modifier", ["Smooth-Step Gradient Modifier"]) - # 5) Create entity with Smooth-Step Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Smooth-Step Gradient Modifier", ["Smooth-Step Gradient Modifier"]) + # 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Threshold Gradient Modifier", ["Threshold Gradient Modifier"]) - # 6) Create entity with Threshold Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Threshold Gradient Modifier", ["Threshold Gradient Modifier"]) + # 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity + clear_entityid_check_position( + "FastNoise Gradient", ["FastNoise Gradient", "Gradient Transform Modifier", "Box Shape"], True + ) - # 7) Create entity with FastNoise Gradient and verify gradient position after clearing pinned entity - clear_entityid_check_position( - "FastNoise Gradient", ["FastNoise Gradient", "Gradient Transform Modifier", "Box Shape"], True - ) + # 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Dither Gradient Modifier", ["Dither Gradient Modifier"], True) - # 8) Create entity with Dither Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Dither Gradient Modifier", ["Dither Gradient Modifier"], True) + # 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity + clear_entityid_check_position("Invert Gradient Modifier", ["Invert Gradient Modifier"]) - # 9) Create entity with Invert Gradient Modifier and verify gradient position after clearing pinned entity - clear_entityid_check_position("Invert Gradient Modifier", ["Invert Gradient Modifier"]) - - # 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity - clear_entityid_check_position( - "Perlin Noise Gradient", ["Perlin Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True - ) + # 10) Create entity with Perlin Noise Gradient and verify gradient position after clearing pinned entity + clear_entityid_check_position( + "Perlin Noise Gradient", ["Perlin Noise Gradient", "Gradient Transform Modifier", "Box Shape"], True + ) -test = TestGradientPreviewSettings() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py index 99a54f614a..3756452710 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py @@ -5,18 +5,6 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - class Scoped: def __init__(self, constructor, destructor, *args): @@ -33,81 +21,84 @@ class TestParams: self.accessed_component = accessed_component -class TestGradientPreviewSettings(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientPreviewSettings_DefaultPinnedEntity", args=["level"]) +def GradientPreviewSettings_DefaultPinnedEntityIsSelf(): + """ + Summary: + This test verifies default values for the pinned entity for Gradient Preview settings. - def run_test(self): - """ - Summary: - This test verifies default values for the pinned entity for Gradient Preview settings. + Expected Behavior: + Pinned entity is self for all gradient generator/modifiers. - Expected Behavior: - Pinned entity is self for all gradient generator/modifiers. + Test Steps: + 1) Open a simple level + 2) Create a new entity in the level + 3) Add each Gradient Generator component to an entity, and verify the Pin Preview to Shape property is set to + self - Test Steps: - 1) Create a new level - 2) Create a new entity in the level - 3) Add each Gradient Generator component to an entity, and verify the Pin Preview to Shape property is set to - self + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity - def execute_test(test_id, function, *args): - if function(*args): - self.log(test_id + ' has Preview pinned to own Entity result: SUCCESS') + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def create_entity(): - return editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - def delete_entity(entity_id): - editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityAndAllDescendants', entity_id) - - def attach_components(component_list, entity_id): - components = [] - for i in component_list: - components.append(hydra.add_component(i, entity_id)) - return components - - def validate_id_is_current(param): - entity_ptr = Scoped(create_entity, delete_entity) - added_components = attach_components(param.required_components, entity_ptr.data) - value = hydra.get_component_property_value(added_components[param.accessed_component], - 'Preview Settings|Pin Preview to Shape') - self.test_success = self.test_success and entity_ptr.data.Equal(value) - return entity_ptr.data.Equal(value) - - param_list = [ - TestParams(['Gradient Transform Modifier', 'Box Shape', 'Perlin Noise Gradient'], 2), - TestParams(['Random Noise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), - TestParams(['FastNoise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), - TestParams(['Dither Gradient Modifier'], 0), - TestParams(['Invert Gradient Modifier'], 0), - TestParams(['Levels Gradient Modifier'], 0), - TestParams(['Posterize Gradient Modifier'], 0), - TestParams(['Smooth-Step Gradient Modifier'], 0), - TestParams(['Threshold Gradient Modifier'], 0) - ] - - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, + def execute_test(test_id, function, *args): + pinned_to_self = ( + f"{test_id} has Preview pinned to self", + f"{test_id} has Preview pinned to a different entity" ) + Report.result(pinned_to_self, function(*args)) - for param in param_list: - execute_test(param.required_components[param.accessed_component], - validate_id_is_current, param) + def create_entity(): + return editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + def delete_entity(entity_id): + editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityAndAllDescendants', entity_id) + + def attach_components(component_list, entity_id): + components = [] + for i in component_list: + components.append(hydra.add_component(i, entity_id)) + return components + + def validate_id_is_current(param): + entity_ptr = Scoped(create_entity, delete_entity) + added_components = attach_components(param.required_components, entity_ptr.data) + value = hydra.get_component_property_value(added_components[param.accessed_component], + 'Preview Settings|Pin Preview to Shape') + return entity_ptr.data.Equal(value) + + param_list = [ + TestParams(['Gradient Transform Modifier', 'Box Shape', 'Perlin Noise Gradient'], 2), + TestParams(['Random Noise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), + TestParams(['FastNoise Gradient', 'Gradient Transform Modifier', 'Box Shape'], 0), + TestParams(['Dither Gradient Modifier'], 0), + TestParams(['Invert Gradient Modifier'], 0), + TestParams(['Levels Gradient Modifier'], 0), + TestParams(['Posterize Gradient Modifier'], 0), + TestParams(['Smooth-Step Gradient Modifier'], 0), + TestParams(['Threshold Gradient Modifier'], 0) + ] + + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + for param in param_list: + execute_test(param.required_components[param.accessed_component], + validate_id_is_current, param) -test = TestGradientPreviewSettings() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientPreviewSettings_DefaultPinnedEntityIsSelf) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py index 6d88f43d5a..8e85345a6f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py @@ -5,92 +5,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.math as math -import azlmbr.paths -import azlmbr.entity as EntityId +def GradientSampling_GradientReferencesAddRemoveSuccessfully(): + """ + Summary: + An existing gradient generator can be pinned and cleared to/from the Gradient Entity Id field -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + Gradient generator is assigned to the Gradient Entity Id field. + Gradient generator is removed from the field. + Test Steps: + 1) Open level + 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" + 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id + field in Gradient Modifier -class TestGradientSampling(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientSampling_GradientReferences", args=["level"]) + 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. - def run_test(self): - """ - Summary: - An existing gradient generator can be pinned and cleared to/from the Gradient Entity Id field + :return: None + """ - Expected Behavior: - Gradient generator is assigned to the Gradient Entity Id field. - Gradient generator is removed from the field. + import azlmbr.math as math + import azlmbr.entity as EntityId - Test Steps: - 1) Open level - 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" - 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id - field in Gradient Modifier + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - 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 - """ - - def modifier_pin_clear_to_gradiententityid(modifier): - entity_position = math.Vector3(125.0, 136.0, 32.0) - component_to_add = [modifier] - gradient_modifier = hydra.Entity(modifier) - gradient_modifier.create_entity(entity_position, component_to_add) - gradient_modifier.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", random_noise.id) - entity = hydra.get_component_property_value( - gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" - ) - if entity.Equal(random_noise.id): - print(f"Gradient Generator is pinned to the {modifier} successfully") - else: - print(f"Failed to pin Gradient Generator to the {modifier}") - hydra.get_set_test(gradient_modifier, 0, "Configuration|Gradient|Gradient Entity Id", EntityId.EntityId()) - entity = hydra.get_component_property_value( - gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" - ) - if entity.Equal(EntityId.EntityId()): - print(f"Gradient Generator is cleared from the {modifier} successfully") - else: - print(f"Failed to clear Gradient Generator from the {modifier}") - - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" + def modifier_pin_clear_to_gradiententityid(modifier): entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] - random_noise = hydra.Entity("Random_Noise") - random_noise.create_entity(entity_position, components_to_add) + component_to_add = [modifier] + gradient_modifier = hydra.Entity(modifier) + gradient_modifier.create_entity(entity_position, component_to_add) + gradient_modifier.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", random_noise.id) + entity = hydra.get_component_property_value( + gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" + ) + gradient_pinned_to_modifier = ( + f"Gradient Generator is pinned to the {modifier} successfully", + f"Failed to pin Gradient Generator to the {modifier}" + ) + Report.result(gradient_pinned_to_modifier, entity.Equal(random_noise.id)) + hydra.get_set_test(gradient_modifier, 0, "Configuration|Gradient|Gradient Entity Id", EntityId.EntityId()) + entity = hydra.get_component_property_value( + gradient_modifier.components[0], "Configuration|Gradient|Gradient Entity Id" + ) + gradient_cleared_from_modifier = ( + f"Gradient Generator is cleared from the {modifier} successfully", + f"Failed to clear Gradient Generator from the {modifier}" + ) + Report.result(gradient_cleared_from_modifier, entity.Equal(EntityId.EntityId())) - # 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id - # field in Gradient Modifier - modifier_pin_clear_to_gradiententityid("Dither Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Invert Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Levels Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Posterize Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Smooth-Step Gradient Modifier") - modifier_pin_clear_to_gradiententityid("Threshold Gradient Modifier") + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] + random_noise = hydra.Entity("Random_Noise") + random_noise.create_entity(entity_position, components_to_add) + + # 3) Create a new entity with Gradient Modifier's, pin and clear the random noise entity id to the Gradient Id + # field in Gradient Modifier + modifier_pin_clear_to_gradiententityid("Dither Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Invert Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Levels Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Posterize Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Smooth-Step Gradient Modifier") + modifier_pin_clear_to_gradiententityid("Threshold Gradient Modifier") -test = TestGradientSampling() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientSampling_GradientReferencesAddRemoveSuccessfully) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py index 26d791495a..f653515a39 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py @@ -5,114 +5,104 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.math as math -import azlmbr.bus as bus -import azlmbr.entity as entity -import azlmbr.paths -import azlmbr.editor as editor - -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientSurfaceTagEmitterDependencies(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__( - self, log_prefix="GradientSurfaceTagEmitter_ComponentDependencies", args=["level"] +def GradientSurfaceTagEmitter_ComponentDependencies(): + """ + Summary: + This test verifies that the Gradient Surface Tag Emitter component is dependent on a gradient component. + + Expected Result: + Gradient Surface Tag Emitter component is disabled until a Gradient Generator, Modifier or Gradient Reference + component (and any sub-dependencies) is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Gradient Surface Tag Emitter component + 3) Verify the component is disabled until a dependent component is also added to the entity + + 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 azlmbr.math as math + import azlmbr.bus as bus + import azlmbr.entity as entity + import azlmbr.editor as editor + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + def is_enabled(EntityComponentIdPair): + return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create an entity with Gradient Surface Tag Emitter component + position = math.Vector3(512.0, 512.0, 32.0) + gradient = hydra.Entity("gradient") + gradient.create_entity(position, ["Gradient Surface Tag Emitter"]) + + # Make sure Gradient Surface Tag Emitter is disabled + gradient_surface_tag_disabled = ( + "Gradient Surface Tag Emitter is Disabled", + "Gradient Surface Tag Emitter is Enabled, but should be Disabled without dependencies met" + ) + Report.result(gradient_surface_tag_disabled, not is_enabled(gradient.components[0])) + + # Verify Gradient Surface Tag Emitter component is enabled after adding Gradient, Generator, Modifier + # or Reference component + new_components_to_add = [ + "Dither Gradient Modifier", + "Gradient Mixer", + "Invert Gradient Modifier", + "Levels Gradient Modifier", + "Posterize Gradient Modifier", + "Smooth-Step Gradient Modifier", + "Threshold Gradient Modifier", + "Altitude Gradient", + "Constant Gradient", + "FastNoise Gradient", + "Image Gradient", + "Perlin Noise Gradient", + "Random Noise Gradient", + "Reference Gradient", + "Shape Falloff Gradient", + "Slope Gradient", + "Surface Mask Gradient", + ] + for component in new_components_to_add: + component_list = ["FastNoise Gradient", "Image Gradient", "Perlin Noise Gradient", "Random Noise Gradient"] + if component in component_list: + for Component in ["Gradient Transform Modifier", "Box Shape"]: + hydra.add_component(Component, gradient.id) + typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [component], + entity.EntityType().Game) + ComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', gradient.id, [typeIdsList[0]]) + Components = ComponentOutcome.GetValue() + ComponentIdPair = Components[0] + gradient_enabled = is_enabled(gradient.components[0]) + new_components_enabled = is_enabled(ComponentIdPair) + dependencies_met = ( + f"{component} and Gradient Surface Tag Emitter are enabled", + f"{component} and Gradient Surface Tag Emitter are disabled" ) + Report.result(dependencies_met, new_components_enabled and gradient_enabled) - def run_test(self): - """ - Summary: - This test verifies that the Gradient Surface Tag Emitter component is dependent on a gradient component. - - Expected Result: - Gradient Surface Tag Emitter component is disabled until a Gradient Generator, Modifier or Gradient Reference - component (and any sub-dependencies) is added to the entity. - - Test Steps: - 1) Open level - 2) Create a new entity with a Gradient Surface Tag Emitter component - 3) Verify the component is disabled until a dependent component is also added to the entity - - 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 - """ - - def is_enabled(EntityComponentIdPair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) - - # Create empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create an entity with Gradient Surface Tag Emitter component - position = math.Vector3(512.0, 512.0, 32.0) - gradient = hydra.Entity("gradient") - gradient.create_entity(position, ["Gradient Surface Tag Emitter"]) - - # Make sure Gradient Surface Tag Emitter is disabled - is_enable = is_enabled(gradient.components[0]) - if not is_enable: - self.log("Gradient Surface Tag Emitter is Disabled") - elif not is_enable: - self.log("Gradient Surface Tag Emitter is Enabled, but should be Disabled without dependencies met") - - # Verify Gradient Surface Tag Emitter component is enabled after adding Gradient, Generator, Modifier - # or Reference component - new_components_to_add = [ - "Dither Gradient Modifier", - "Gradient Mixer", - "Invert Gradient Modifier", - "Levels Gradient Modifier", - "Posterize Gradient Modifier", - "Smooth-Step Gradient Modifier", - "Threshold Gradient Modifier", - "Altitude Gradient", - "Constant Gradient", - "FastNoise Gradient", - "Image Gradient", - "Perlin Noise Gradient", - "Random Noise Gradient", - "Reference Gradient", - "Shape Falloff Gradient", - "Slope Gradient", - "Surface Mask Gradient", - ] - for component in new_components_to_add: - component_list = ["FastNoise Gradient", "Image Gradient", "Perlin Noise Gradient", "Random Noise Gradient"] - if component in component_list: - for Component in ["Gradient Transform Modifier", "Box Shape"]: - hydra.add_component(Component, gradient.id) - typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [component], - entity.EntityType().Game) - ComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', gradient.id, [typeIdsList[0]]) - Components = ComponentOutcome.GetValue() - ComponentIdPair = Components[0] - gradient_enabled = new_components_enabled = False - gradient_enabled = is_enabled(gradient.components[0]) - new_components_enabled = is_enabled(ComponentIdPair) - if new_components_enabled and gradient_enabled: - self.log(f"{component} and Gradient Surface Tag Emitter are enabled") - else: - self.log(f"{component} and Gradient Surface Tag Emitter are disabled") - if component in component_list: - hydra.remove_component("Gradient Transform Modifier", gradient.id) - hydra.remove_component("Box Shape", gradient.id) - hydra.remove_component(component, gradient.id) + if component in component_list: + hydra.remove_component("Gradient Transform Modifier", gradient.id) + hydra.remove_component("Box Shape", gradient.id) + hydra.remove_component(component, gradient.id) -test = TestGradientSurfaceTagEmitterDependencies() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientSurfaceTagEmitter_ComponentDependencies) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py index 44c9792296..90840a135d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py @@ -5,75 +5,69 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.math as math -import azlmbr.paths -import azlmbr.surface_data as surface_data +def GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(): + """ + Summary: + Entity with Gradient Surface Tag Emitter and Reference Gradient components is created. + And new surface tag has been added and removed. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + A new Surface Tag can be added and removed from the component + + Test Steps: + 1) Open level + 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. + 3) Add/ remove Surface Tags + + 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 azlmbr.math as math + import azlmbr.surface_data as surface_data + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Gradient Surface Tag Emitter", "Reference Gradient"] + entity = hydra.Entity("entity") + entity.create_entity(entity_position, components_to_add) + + # 3) Add/ remove Surface Tags + tag = surface_data.SurfaceTag() + tag.SetTag("water") + pte = hydra.get_property_tree(entity.components[0]) + path = "Configuration|Extended Tags" + pte.add_container_item(path, 0, tag) + success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1, 1.0) + tag_added_to_container = ( + "Successfully added surface tag", + "Failed to add surface tag" + ) + Report.result(tag_added_to_container, success) + pte.remove_container_item(path, 0) + success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0, 1.0) + tag_removed_from_container = ( + "Successfully removed surface tag", + "Failed to remove surface tag" + ) + Report.result(tag_removed_from_container, success) -class TestGradientSurfaceTagEmitter(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSucessfully", - args=["level"]) +if __name__ == "__main__": - def run_test(self): - """ - Summary: - Entity with Gradient Surface Tag Emitter and Reference Gradient components is created. - And new surface tag has been added and removed. - - Expected Behavior: - A new Surface Tag can be added and removed from the component + from editor_python_test_tools.utils import Report + Report.start_test(GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully) - Test Steps: - 1) Open level - 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. - 3) Add/ remove Surface Tags - - 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 - """ - - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. - entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Gradient Surface Tag Emitter", "Reference Gradient"] - entity = hydra.Entity("entity") - entity.create_entity(entity_position, components_to_add) - - # 3) Add/ remove Surface Tags - tag = surface_data.SurfaceTag() - tag.SetTag("water") - pte = hydra.get_property_tree(entity.components[0]) - path = "Configuration|Extended Tags" - pte.add_container_item(path, 0, tag) - success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1) - self.test_success = self.test_success and success - print(f"Added SurfaceTag: container count is {pte.get_container_count(path).GetValue()}") - pte.remove_container_item(path, 0) - success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0) - self.test_success = self.test_success and success - print(f"Removed SurfaceTag: container count is {pte.get_container_count(path).GetValue()}") - - -test = TestGradientSurfaceTagEmitter() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py index b5f342a15f..5e6df4d52f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py @@ -5,118 +5,102 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.entity as EntityId +def GradientTransform_ComponentIncompatibleWithExpectedGradients(): + """ + Summary: + A New level is created. A New entity is created with components Gradient Transform Modifier and Box Shape. + Adding components Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape + Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + All added components are disabled and inform the user that they are incompatible with the Gradient Transform + Modifier + Test Steps: + 1) Create level + 2) Create a new entity with components Gradient Transform Modifier and Box Shape + 3) Make sure all components are enabled in Entity + 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape + Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity + 5) Make sure all newly added components are disabled -class TestGradientTransform_ComponentIncompatibleWithExpectedGradients(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransform_ComponentIncompatibleWithExpectedGradients", - args=["level"]) + 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. - def run_test(self): - """ - Summary: - A New level is created. A New entity is created with components Gradient Transform Modifier and Box Shape. - Adding components Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape - Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity. + :return: None + """ - Expected Behavior: - All added components are disabled and inform the user that they are incompatible with the Gradient Transform - Modifier + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - Test Steps: - 1) Create level - 2) Create a new entity with components Gradient Transform Modifier and Box Shape - 3) Make sure all components are enabled in Entity - 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape - Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity - 5) Make sure all newly added components are disabled + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - 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. + def is_enabled(EntityComponentIdPair): + return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) - :return: None - """ + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - def is_enabled(EntityComponentIdPair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) + # 2) Create a new entity with components Gradient Transform Modifier and Box Shape + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Gradient Transform Modifier", "Box Shape"] + gradient_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + gradient = hydra.Entity("gradient", gradient_id) - # 1) Create level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, + gradient.components = [] + + for component in components_to_add: + gradient.components.append(hydra.add_component(component, gradient_id)) + entity_created = ( + "Entity created successfully", + "Failed to create entity" + ) + Report.critical_result(entity_created, gradient_id.isValid()) + + # 3) Make sure all components are enabled in Entity + index = 0 + for component in components_to_add: + components_enabled = ( + f"{component} is enabled", + f"{component} is unexpectedly disabled" ) + Report.critical_result(components_enabled, is_enabled(gradient.components[index])) + index += 1 - # 2) Create a new entity with components Gradient Transform Modifier and Box Shape - entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Gradient Transform Modifier", "Box Shape"] - gradient_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + # 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape + # Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity + new_components_to_add = [ + "Constant Gradient", + "Altitude Gradient", + "Gradient Mixer", + "Reference Gradient", + "Shape Falloff Gradient", + "Slope Gradient", + "Surface Mask Gradient", + ] + new_components_enabled = False + for component in new_components_to_add: + gradient.components.append(hydra.add_component(component, gradient_id)) + gradient_components_disabled = ( + f"{component} is disabled", + f"{component} is enabled, but should be disabled" ) - gradient = hydra.Entity("gradient", gradient_id) - - gradient.components = [] - - for component in components_to_add: - gradient.components.append(hydra.add_component(component, gradient_id)) - if gradient_id.isValid(): - self.log("New Entity Created") - - # 3) Make sure all components are enabled in Entity - index = 0 - for component in components_to_add: - is_enable = is_enabled(gradient.components[index]) - if is_enable: - self.log(f"{component} is Enabled") - self.test_success = self.test_success and is_enable - elif not is_enable: - self.log(f"{component} is disabled, but it should be enabled") - self.test_success = self.test_success and is_enable - break - index += 1 - - # 4) Add Constant Gradient, Altitude Gradient, Gradient Mixer, Reference Gradient, Shape - # Falloff Gradient, Slope Gradient and Surface Mask Gradient to the same entity - new_components_to_add = [ - "Constant Gradient", - "Altitude Gradient", - "Gradient Mixer", - "Reference Gradient", - "Shape Falloff Gradient", - "Slope Gradient", - "Surface Mask Gradient", - ] - index = 2 - new_components_enabled = False - for component in new_components_to_add: - gradient.components.append(hydra.add_component(component, gradient_id)) - new_components_enabled = is_enabled(gradient.components[index]) - if new_components_enabled: - self.log(f"{component} is enabled, but should be disabled") - break + Report.result(gradient_components_disabled, not is_enabled(gradient.components[2])) + if not is_enabled(gradient.components[2]): editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", component) - # 5) Make sure all newly added components are disabled - if not new_components_enabled: - self.log("All newly added components are incompatible and disabled") - self.test_success = self.test_success and not new_components_enabled +if __name__ == "__main__": -test = TestGradientTransform_ComponentIncompatibleWithExpectedGradients() -test.run() + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_ComponentIncompatibleWithExpectedGradients) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py index 54270c5ee5..fd65996fdd 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py @@ -5,104 +5,88 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.entity as EntityId +def GradientTransform_ComponentIncompatibleWithSpawners(): + """ + Summary: + A simple level is opened. A New entity is created with components Gradient Transform Modifier and Box Shape. + Adding a component Vegetation Layer Spawner to the same entity. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + The Vegetation Layer Spawner is deactivated and it is communicated that it is incompatible with Gradient + Transform Modifier + Test Steps: + 1) Open a simple level + 2) Create a new entity with components Gradient Transform Modifier and Box Shape + 3) Make sure all components are enabled in Entity + 4) Add Vegetation Layer Spawner to the same entity + 5) Make sure newly added component is disabled -class TestGradientTransform_ComponentIncompatibleWithSpawners(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransform_ComponentIncompatibleWithSpawners", - args=["level"]) + 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. - def run_test(self): - """ - Summary: - A New level is created. A New entity is created with components Gradient Transform Modifier and Box Shape. - Adding a component Vegetation Layer Spawner to the same entity. + :return: None + """ - Expected Behavior: - The Vegetation Layer Spawner is deactivated and it is communicated that it is incompatible with Gradient - Transform Modifier + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - Test Steps: - 1) Create level - 2) Create a new entity with components Gradient Transform Modifier and Box Shape - 3) Make sure all components are enabled in Entity - 4) Add Vegetation Layer Spawner to the same entity - 5) Make sure newly added component is disabled + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - 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. + def is_enabled(EntityComponentIdPair): + return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) - :return: None - """ + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - def is_enabled(EntityComponentIdPair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) + # 2) Create a new entity with components Gradient Transform Modifier and Box Shape + entity_position = math.Vector3(125.0, 136.0, 32.0) + components_to_add = ["Gradient Transform Modifier", "Box Shape"] + gradient_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + gradient = hydra.Entity("gradient", gradient_id) - # 1) Create level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, + gradient.components = [] + + for component in components_to_add: + gradient.components.append(hydra.add_component(component, gradient_id)) + entity_created = ( + "Entity created successfully", + "Failed to create entity" + ) + Report.critical_result(entity_created, gradient_id.isValid()) + + # 3) Make sure all components are enabled in Entity + index = 0 + for component in components_to_add: + components_enabled = ( + f"{component} is enabled", + f"{component} is unexpectedly disabled" ) + Report.critical_result(components_enabled, is_enabled(gradient.components[index])) + index += 1 - # 2) Create a new entity with components Gradient Transform Modifier and Box Shape - entity_position = math.Vector3(125.0, 136.0, 32.0) - components_to_add = ["Gradient Transform Modifier", "Box Shape"] - gradient_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() - ) - gradient = hydra.Entity("gradient", gradient_id) + # 4) Add Vegetation Layer Spawner to the same entity + gradient.components.append(hydra.add_component("Vegetation Layer Spawner", gradient_id)) - gradient.components = [] - - for component in components_to_add: - gradient.components.append(hydra.add_component(component, gradient_id)) - if gradient_id.isValid(): - self.log("New Entity Created") - - # 3) Make sure all components are enabled in Entity - index = 0 - for component in components_to_add: - is_enable = is_enabled(gradient.components[index]) - if is_enable: - self.log(f"{component} is Enabled") - self.test_success = self.test_success and is_enable - elif not is_enable: - self.log(f"{component} is Disabled. But It should be Enabled in an Entity") - self.test_success = self.test_success and is_enable - break - index += 1 - - # 4) Add Vegetation Layer Spawner to the same entity - new_component_to_add = "Vegetation Layer Spawner" - index = 2 - gradient.components.append(hydra.add_component(new_component_to_add, gradient_id)) - new_component_enabled = is_enabled(gradient.components[index]) - - # 5) Make sure newly added component is disabled - if not new_component_enabled: - self.log(f"{new_component_to_add} is incompatible and disabled") - self.test_success = self.test_success and not new_component_enabled - elif new_component_enabled: - self.log(f"{new_component_to_add} is compatible and enabled. But It should be Incompatible and disabled") - self.test_success = self.test_success and new_component_enabled + # 5) Make sure newly added component is disabled + spawner_component_disabled = ( + "Spawner component is disabled", + "Spawner component is unexpectedly enabled" + ) + Report.result(spawner_component_disabled, not is_enabled(gradient.components[2])) -test = TestGradientTransform_ComponentIncompatibleWithSpawners() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_ComponentIncompatibleWithSpawners) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py index 94647a0b6f..530503db86 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py @@ -5,87 +5,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -""" -C3430292: Frequency Zoom can manually be set higher than 8. -""" -import os -import sys - -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths -import azlmbr.entity as EntityId - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper +class Tests: + entity_created = ( + "Entity created successfully", + "Failed to create entity" + ) + components_added = ( + "All expected components added to entity", + "Failed to add expected components to entity" + ) + higher_zoom_value_set = ( + "Frequency Zoom is equal to expected value", + "Frequency Zoom is not equal to expected value" + ) -class TestGradientTransformFrequencyZoom(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransform_FrequencyZoomBeyondSliders", args=["level"]) +def GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(): + """ + Summary: + Frequency Zoom can manually be set higher than 8 in a random noise gradient - def run_test(self): - """ - Summary: - Frequency Zoom can manually be set higher than 8 in a random noise gradient + Expected Behavior: + The value properly changes, despite the value being outside of the slider limit - Expected Behavior: - The value properly changes, despite the value being outside of the slider limit + Test Steps: + 1) Open level + 2) Create entity + 3) Add components to the entity + 4) Set the frequency value of the component + 5) Verify if the frequency value is set to higher value - Test Steps: - 1) Open level - 2) Create entity - 3) Add components to the entity - 4) Set the frequency value of the component - 5) Verify if the frequency value is set to higher value + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.math as math + import azlmbr.entity as EntityId - # 1) Open level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # 2) Create entity - entity_position = math.Vector3(125.0, 136.0, 32.0) - entity_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() - ) - if entity_id.IsValid(): - print("Entity Created") + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # 3) Add components to the entity - components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] - entity = hydra.Entity("entity", entity_id) - entity.components = [] - for component in components_to_add: - entity.components.append(hydra.add_component(component, entity_id)) - print("Components added to the entity") + # 2) Create entity + entity_position = math.Vector3(125.0, 136.0, 32.0) + entity_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + Report.critical_result(Tests.entity_created, entity_id.IsValid()) - # 4) Set the frequency value of the component - hydra.get_set_test(entity, 1, "Configuration|Frequency Zoom", 10) + # 3) Add components to the entity + components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] + entity = hydra.Entity("entity", entity_id) + entity.components = [] + for component in components_to_add: + entity.components.append(hydra.add_component(component, entity_id)) + Report.critical_result(Tests.components_added, len(entity.components) == 3) - # 5) Verify if the frequency value is set to higher value - curr_value = hydra.get_component_property_value(entity.components[1], "Configuration|Frequency Zoom") - if curr_value == 10.0: - print("Frequency Zoom is equal to expected value") - else: - print("Frequency Zoom is not equal to expected value") + # 4) Set the frequency value of the component + hydra.get_set_test(entity, 1, "Configuration|Frequency Zoom", 10) + + # 5) Verify if the frequency value is set to higher value + curr_value = hydra.get_component_property_value(entity.components[1], "Configuration|Frequency Zoom") + Report.result(Tests.higher_zoom_value_set, curr_value == 10.0) -test = TestGradientTransformFrequencyZoom() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py index c9cfc225d1..09cce359d5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py @@ -4,73 +4,71 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestGradientTransformRequiresShape(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientTransformRequiresShape", args=["level"]) - - def run_test(self): - """ - Summary: - This test verifies that the Gradient Transform Modifier component is dependent on a shape component. - - Expected Result: - Gradient Transform Modifier component is disabled until a shape component is added to the entity. - - Test Steps: - 1) Open level - 2) Create a new entity with a Gradient Transform Modifier component - 3) Verify the component is disabled until a shape component is also added to the entity - - 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 - """ - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - # Add a Gradient Transform Component (that will be disabled since there is no shape on the Entity) - gradient_transform_component = hydra.add_component('Gradient Transform Modifier', entity_id) - - # Verify the Gradient Transform Component is not active before adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) - self.test_success = self.test_success and not active - if not active: - self.log("Gradient Transform component is not active without a Shape component on the Entity") - - # Add a Shape component to the same Entity - hydra.add_component('Box Shape', entity_id) - - # Check if the Gradient Transform Component is active now after adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) - self.test_success = self.test_success and active - if active: - self.log("Gradient Transform Modifier component is active now that the Entity has a Shape") +class Tests: + disabled_without_shape = ( + "Gradient Transform Modifier component is disabled without a Shape component on the Entity", + "Gradient Transform Modifier component is unexpectedly enabled without a Shape component on the Entity", + ) + enabled_with_shape = ( + "Gradient Transform Modifier component is enabled now that the Entity has a Shape", + "Gradient Transform Modifier component is still disabled alongside a Shape component", + ) -test = TestGradientTransformRequiresShape() -test.run() +def GradientTransform_RequiresShape(): + """ + Summary: + This test verifies that the Gradient Transform Modifier component is dependent on a shape component. + + Expected Result: + Gradient Transform Modifier component is disabled until a shape component is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Gradient Transform Modifier component + 3) Verify the component is disabled until a shape component is also added to the entity + + 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 azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + # Add a Gradient Transform Component (that will be disabled since there is no shape on the Entity) + gradient_transform_component = hydra.add_component('Gradient Transform Modifier', entity_id) + + # Verify the Gradient Transform Component is not active before adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) + Report.result(Tests.disabled_without_shape, not active) + + # Add a Shape component to the same Entity + hydra.add_component('Box Shape', entity_id) + + # Check if the Gradient Transform Component is active now after adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', gradient_transform_component) + Report.result(Tests.enabled_with_shape, active) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientTransform_RequiresShape) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py index 1063260550..42458665e1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py @@ -5,89 +5,91 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__))) -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.entity as EntityId -import azlmbr.editor as editor -import azlmbr.math as math -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper +class Tests: + image_gradient_entity_created = ( + "Image Gradient entity created", + "Failed to create Image Gradient entity", + ) + image_gradient_asset_found = ( + "image_grad_test_gsi.png was found in the workspace", + "image_grad_test_gsi.png was not found in the workspace" + ) + image_gradient_assigned = ( + "Successfully assigned image gradient asset", + "Failed to assign image gradient asset" + ) -class TestImageGradient(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ImageGradient_ProcessedImageAssignedSucessfully", - args=["level"]) +def ImageGradient_ProcessedImageAssignedSuccessfully(): + """ + Summary: + Level created with Entity having Image Gradient and Gradient Transform Modifier components. + Save any new image to your workspace with the suffix "_gsi" and assign as image asset. - def run_test(self): - """ - Summary: - Level created with Entity having Image Gradient and Gradient Transform Modifier components. - Save any new image to your workspace with the suffix "_gsi" and assign as image asset. - - Expected Behavior: - Image can be assigned as the Image Asset for the Image as Gradient component. + Expected Behavior: + Image can be assigned as the Image Asset for the Image as Gradient component. - Test Steps: - 1) Create level - 2) Create an entity with Image Gradient and Gradient Transform Modifier components. - 3) Assign the newly processed gradient image as Image asset. + Test Steps: + 1) Open a level + 2) Create an entity with Image Gradient and Gradient Transform Modifier components. + 3) Assign the newly processed gradient image as Image asset. - 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. + 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 - """ + :return: None + """ - # 1) Create level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + import os - # 2) Create an entity with Image Gradient and Gradient Transform Modifier components - components_to_add = ["Image Gradient", "Gradient Transform Modifier", "Box Shape"] - entity_position = math.Vector3(512.0, 512.0, 32.0) - new_entity_id = editor.ToolsApplicationRequestBus( - bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() - ) - if new_entity_id.IsValid(): - print("Image Gradient Entity created") - image_gradient_entity = hydra.Entity("Image Gradient Entity", new_entity_id) - image_gradient_entity.components = [] - for component in components_to_add: - image_gradient_entity.add_component(component) + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.entity as EntityId + import azlmbr.editor as editor + import azlmbr.math as math - # 3) Assign the processed gradient signal image as the Image Gradient's image asset and verify success + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # First, check for the base image in the workspace - base_image = "image_grad_test_gsi.png" - base_image_path = os.path.join("AutomatedTesting", "Assets", "ImageGradients", base_image) - if os.path.isfile(base_image_path): - print(f"{base_image} was found in the workspace") + # 1) Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Next, assign the processed image to the Image Gradient's Image Asset property - processed_image_path = os.path.join("Assets", "ImageGradients", "image_grad_test_gsi.gradimage") - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", processed_image_path, math.Uuid(), - False) - hydra.get_set_test(image_gradient_entity, 0, "Configuration|Image Asset", asset_id) + # 2) Create an entity with Image Gradient and Gradient Transform Modifier components + components_to_add = ["Image Gradient", "Gradient Transform Modifier", "Box Shape"] + entity_position = math.Vector3(512.0, 512.0, 32.0) + new_entity_id = editor.ToolsApplicationRequestBus( + bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() + ) + Report.critical_result(Tests.image_gradient_entity_created, new_entity_id.IsValid()) + image_gradient_entity = hydra.Entity("Image Gradient Entity", new_entity_id) + image_gradient_entity.components = [] + for component in components_to_add: + image_gradient_entity.add_component(component) - # Finally, verify if the gradient image is assigned as the Image Asset - success = hydra.get_component_property_value(image_gradient_entity.components[0], "Configuration|Image Asset") == asset_id - self.test_success = self.test_success and success + # 3) Assign the processed gradient signal image as the Image Gradient's image asset and verify success + + # First, check for the base image in the workspace + base_image = "image_grad_test_gsi.png" + base_image_path = os.path.join("AutomatedTesting", "Assets", "ImageGradients", base_image) + Report.critical_result(Tests.image_gradient_asset_found, os.path.isfile(base_image_path)) + + # Next, assign the processed image to the Image Gradient's Image Asset property + processed_image_path = os.path.join("Assets", "ImageGradients", "image_grad_test_gsi.gradimage") + asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", processed_image_path, math.Uuid(), + False) + hydra.get_set_test(image_gradient_entity, 0, "Configuration|Image Asset", asset_id) + + # Finally, verify if the gradient image is assigned as the Image Asset + success = hydra.get_component_property_value(image_gradient_entity.components[0], "Configuration|Image Asset") == asset_id + Report.result(Tests.image_gradient_assigned, success) -test = TestImageGradient() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ImageGradient_ProcessedImageAssignedSuccessfully) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py index 2c6ac8d15b..3b832d160a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py @@ -4,74 +4,72 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -class TestImageGradientRequiresShape(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ImageGradientRequiresShape", args=["level"]) - - def run_test(self): - """ - Summary: - This test verifies that the Image Gradient component is dependent on a shape component. - - Expected Result: - Gradient Transform Modifier component is disabled until a shape component is added to the entity. - - Test Steps: - 1) Open level - 2) Create a new entity with a Image Gradient component - 3) Verify the component is disabled until a shape component is also added to the entity - - 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 - """ - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create a new Entity in the level - entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - # Add an Image Gradient and Gradient Transform Component (should be disabled until a Shape exists on the Entity) - image_gradient_component = hydra.add_component('Image Gradient', entity_id) - hydra.add_component('Gradient Transform Modifier', entity_id) - - # Verify the Image Gradient Component is not active before adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) - self.test_success = self.test_success and not active - if not active: - self.log("Image Gradient component is not active without a Shape component on the Entity") - - # Add a Shape component to the same Entity - hydra.add_component('Box Shape', entity_id) - - # Check if the Image Gradient Component is active now after adding the Shape - active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) - self.test_success = self.test_success and active - if active: - self.log("Image Gradient component is active now that the Entity has a Shape") +class Tests: + disabled_without_shape = ( + "Image Gradient component is disabled without a Shape component on the Entity", + "Image Gradient component is unexpectedly enabled without a Shape component on the Entity", + ) + enabled_with_shape = ( + "Image Gradient component is enabled now that the Entity has a Shape", + "Image Gradient component is still disabled alongside a Shape component", + ) -test = TestImageGradientRequiresShape() -test.run() +def ImageGradient_RequiresShape(): + """ + Summary: + This test verifies that the Image Gradient component is dependent on a shape component. + + Expected Result: + Gradient Transform Modifier component is disabled until a shape component is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Image Gradient component + 3) Verify the component is disabled until a shape component is also added to the entity + + 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 azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create a new Entity in the level + entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + # Add an Image Gradient and Gradient Transform Component (should be disabled until a Shape exists on the Entity) + image_gradient_component = hydra.add_component('Image Gradient', entity_id) + hydra.add_component('Gradient Transform Modifier', entity_id) + + # Verify the Image Gradient Component is not active before adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) + Report.result(Tests.disabled_without_shape, not active) + + # Add a Shape component to the same Entity + hydra.add_component('Box Shape', entity_id) + + # Check if the Image Gradient Component is active now after adding the Shape + active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', image_gradient_component) + Report.result(Tests.enabled_with_shape, active) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ImageGradient_RequiresShape) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py new file mode 100644 index 0000000000..21eecf642c --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic.py @@ -0,0 +1,71 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest +import sys + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') +from base import TestAutomationBase + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_GradientGenerators_Incompatibilities(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientGenerators_Incompatibilities as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientModifiers_Incompatibilities(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientModifiers_Incompatibilities as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientSampling_GradientReferencesAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientSampling_GradientReferencesAddRemoveSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientSurfaceTagEmitter_ComponentDependencies(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientSurfaceTagEmitter_ComponentDependencies as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_RequiresShape(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_RequiresShape as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_ComponentIncompatibleWithSpawners(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module + self._run_test(request, workspace, editor, test_module) + + def test_GradientTransform_ComponentIncompatibleWithExpectedGradients(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithExpectedGradients as test_module + self._run_test(request, workspace, editor, test_module) + + def test_ImageGradient_RequiresShape(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ImageGradient_RequiresShape as test_module + self._run_test(request, workspace, editor, test_module) + + def test_ImageGradient_ProcessedImageAssignedSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ImageGradient_ProcessedImageAssignedSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py new file mode 100644 index 0000000000..514504d324 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_GradientSignal_Periodic_Optimized.py @@ -0,0 +1,55 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import pytest + +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + + class test_GradientGenerators_Incompatibilities(EditorSharedTest): + from .EditorScripts import GradientGenerators_Incompatibilities as test_module + + class test_GradientModifiers_Incompatibilities(EditorSharedTest): + from .EditorScripts import GradientModifiers_Incompatibilities as test_module + + class test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(EditorSharedTest): + from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module + + class test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(EditorSharedTest): + from .EditorScripts import GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin as test_module + + class test_GradientSampling_GradientReferencesAddRemoveSuccessfully(EditorSharedTest): + from .EditorScripts import GradientSampling_GradientReferencesAddRemoveSuccessfully as test_module + + class test_GradientSurfaceTagEmitter_ComponentDependencies(EditorSharedTest): + from .EditorScripts import GradientSurfaceTagEmitter_ComponentDependencies as test_module + + class test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorSharedTest): + from .EditorScripts import GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module + + class test_GradientTransform_RequiresShape(EditorSharedTest): + from .EditorScripts import GradientTransform_RequiresShape as test_module + + class test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(EditorSharedTest): + from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module + + class test_GradientTransform_ComponentIncompatibleWithSpawners(EditorSharedTest): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module + + class test_GradientTransform_ComponentIncompatibleWithExpectedGradients(EditorSharedTest): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithExpectedGradients as test_module + + class test_ImageGradient_RequiresShape(EditorSharedTest): + from .EditorScripts import ImageGradient_RequiresShape as test_module + + class test_ImageGradient_ProcessedImageAssignedSuccessfully(EditorSharedTest): + from .EditorScripts import ImageGradient_ProcessedImageAssignedSuccessfully as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py index 913dc46fa5..9703423901 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py @@ -5,144 +5,147 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + dependencies_added = ( + "Node created new Entity with all required components", + "Failed to create node with all required components" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestAreaNodeComponentDependency(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="AreaNodeComponentDependency", args=["level"]) +def AreaNodes_DependentComponentsAdded(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with + proper dependent components. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with - proper dependent components. + Expected Behavior: + All expected component dependencies are met when adding an area node to a graph. - Expected Behavior: - All expected component dependencies are met when adding an area node to a graph. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure the proper dependent components are added - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the area nodes to the graph area, and ensure the proper dependent components are added + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding these vegetation area nodes has the main target Vegetation Layer Component - # as well as automatically adding all required dependency components - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Vegetation area mapping with the key being the node name and the value is the - # expected Components that should be added to the Entity created for the node - areas = { - 'SpawnerAreaNode': [ - 'Vegetation Layer Spawner', - 'Vegetation Asset List', - 'Vegetation Reference Shape' - ], - 'MeshBlockerAreaNode': [ - 'Vegetation Layer Blocker (Mesh)', - 'Mesh' - ], - 'BlockerAreaNode': [ - 'Vegetation Layer Blocker', - 'Vegetation Reference Shape' - ] - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in areas: - componentNames.extend(areas[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding these vegetation area nodes has the main target Vegetation Layer Component + # as well as automatically adding all required dependency components + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for the vegetation areas that have additional required dependencies and check if - # the Entity created by adding the node has the appropriate component and required - # additional components added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in areas: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Vegetation area mapping with the key being the node name and the value is the + # expected Components that should be added to the Entity created for the node + areas = { + 'SpawnerAreaNode': [ + 'Vegetation Layer Spawner', + 'Vegetation Asset List', + 'Vegetation Reference Shape' + ], + 'MeshBlockerAreaNode': [ + 'Vegetation Layer Blocker (Mesh)', + 'Mesh' + ], + 'BlockerAreaNode': [ + 'Vegetation Layer Blocker', + 'Vegetation Reference Shape' + ] + } - components = areas[nodeName] - success = False - for component in components: - componentTypeId = componentTypeIds[component] - success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - if not success: - break - self.test_success = self.test_success and success - if success: - self.log("{node} created new Entity with all required components".format(node=nodeName)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in areas: + componentNames.extend(areas[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - x += 40.0 - y += 40.0 + # Create nodes for the vegetation areas that have additional required dependencies and check if + # the Entity created by adding the node has the appropriate component and required + # additional components added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in areas: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + components = areas[nodeName] + success = False + for component in components: + componentTypeId = componentTypeIds[component] + success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + if not success: + break + Report.info(nodeName) + Report.result(Tests.dependencies_added, success) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestAreaNodeComponentDependency() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(AreaNodes_DependentComponentsAdded) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py index 2ee0c60a7d..f3f4a1862d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py @@ -5,125 +5,129 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityCreate", args=["level"]) +def AreaNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging area nodes to graph area. - Expected Behavior: - New entities are created when dragging area nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the area nodes to the graph area, and ensure a new entity is created + 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. - 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 + """ - :return: None - """ - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Listen for entity creation notifications so we can check if the entity created - # from adding vegetation area nodes has the appropriate Vegetation Layer Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Vegetation Area mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - areas = { - 'AreaBlenderNode': 'Vegetation Layer Blender', - 'BlockerAreaNode': 'Vegetation Layer Blocker', - 'MeshBlockerAreaNode': 'Vegetation Layer Blocker (Mesh)', - 'SpawnerAreaNode': 'Vegetation Layer Spawner' - } + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in areas: - componentNames.append(areas[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the vegetation areas we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in areas: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding vegetation area nodes has the appropriate Vegetation Layer Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - areaComponent = areas[nodeName] - componentTypeId = componentTypeIds[areaComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, component=areaComponent)) + # Vegetation Area mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + areas = { + 'AreaBlenderNode': 'Vegetation Layer Blender', + 'BlockerAreaNode': 'Vegetation Layer Blocker', + 'MeshBlockerAreaNode': 'Vegetation Layer Blocker (Mesh)', + 'SpawnerAreaNode': 'Vegetation Layer Spawner' + } - x += 40.0 - y += 40.0 + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in areas: + componentNames.append(areas[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Stop listening for entity creation notifications - handler.disconnect() + # Create nodes for all the vegetation areas we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in areas: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + + areaComponent = areas[nodeName] + componentTypeId = componentTypeIds[areaComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) + Report.info(f"Node: {nodeName} | Component: {areaComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(AreaNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py index b9960447c6..f8b0539759 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py @@ -5,123 +5,128 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestAreaNodeEntityDelete(EditorTestHelper): +def AreaNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when area nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when area nodes are deleted from a graph. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the area nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - :return: None - """ - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Vegetation Area mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - areas = [ - 'AreaBlenderNode', - 'BlockerAreaNode', - 'MeshBlockerAreaNode', - 'SpawnerAreaNode', - ] + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in areas: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + # Vegetation Area mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + areas = [ + 'AreaBlenderNode', + 'BlockerAreaNode', + 'MeshBlockerAreaNode', + 'SpawnerAreaNode', + ] - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in areas: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestAreaNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(AreaNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py index a704cc9dab..cc40d8b861 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py @@ -5,197 +5,209 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.math as math -import azlmbr.slice as slice -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper +class Tests: + slice_instantiated = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + lc_entity_found = ( + "LandscapeCanvas entity found", + "Failed to find LandscapeCanvas entity" + ) + spawner_entity_found = ( + "BushSpawner entity found", + "Failed to find BushSpawner entity" + ) + dist_filter_component_found = ( + "Vegetation Distribution Filter component on BushSpawner entity found", + "Failed to find Distribution Filter component on BushSpawner entity" + ) + existing_graph_opened = ( + "Opened existing graph from slice", + "Failed to open existing graph" + ) + dist_filter_node_found = ( + "Vegetation Distribution Filter node found on graph", + "Failed to find Distribution Filter node on graph" + ) + alt_filter_component_found = ( + "Vegetation Altitude Filter component on BushSpawner entity found", + "Failed to find Altitude Filter component on BushSpawner entity" + ) + alt_filter_node_found = ( + "Vegetation Altitude Filter node found on graph", + "Failed to find Altitude Filter node on graph" + ) + dist_filter_component_removed = ( + "Vegetation Distribution Filter component removed from BushSpawner entity", + "Failed to remove Distribution Filter component from BushSpawner entity" + ) + dist_filter_node_removed = ( + "Vegetation Distribution Filter node removed from graph", + "Failed to remove Distribution Filter node from graph" + ) + child_entity_added = ( + "New entity successfully added as a child of the BushSpawner entity", + "New entity added with an unexpected parent" + ) + box_shape_component_found = ( + "Box Shape component on Box entity found", + "Failed to find Box Shape component on Box entity" + ) + box_shape_node_found = ( + "Box Shape node found on graph", + "Failed to find Box Shape node on graph" + ) -class TestComponentUpdatesUpdateGraph(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ComponentUpdatesUpdateGraph", args=["level"]) +def ComponentUpdates_UpdateGraph(): + """ + Summary: + This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of + Landscape Canvas. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of - Landscape Canvas. + Expected Behavior: + Graphs properly reflect component changes made to entities outside of Landscape Canvas. - Expected Behavior: - Graphs properly reflect component changes made to entities outside of Landscape Canvas. + Test Steps: + 1. Open Level + 2. Find LandscapeCanvas named entity + 3. Ensure Vegetation Distribution Component is present on the BushSpawner entity + 4. Open graph and ensure Distribution Filter wrapped node is present + 5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector + 6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is + no longer present in the graph + 7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector + 8. Ensure Altitude Filter was added to the BushSpawner node in the open graph + 9. Add a new entity with unique name as a child of the Landscape Canvas entity + 10. Add a Box Shape component to the new child entity + 11. Ensure Box Shape node is present on the open graph - Test Steps: - 1. Open Level - 2. Find LandscapeCanvas named entity - 3. Ensure Vegetation Distribution Component is present on the BushSpawner entity - 4. Open graph and ensure Distribution Filter wrapped node is present - 5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector - 6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is - no longer present in the graph - 7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector - 8. Ensure Altitude Filter was added to the BushSpawner node in the open graph - 9. Add a new entity with unique name as a child of the Landscape Canvas entity - 10. Add a Box Shape component to the new child entity - 11. Ensure Box Shape node is present on the open graph + 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. - 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 + """ - :return: None - """ + import os - # Create a new empty level and instantiate LC_BushFlowerBlender.slice - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - transform = math.Transform_CreateIdentity() - position = math.Vector3(64.0, 64.0, 32.0) - transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - self.test_success = self.test_success and test_slice.IsValid() - if test_slice.IsValid(): - self.log("Slice spawned!") + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.math as math + import azlmbr.slice as slice - # Find root entity in the loaded level - search_filter = entity.SearchFilter() - search_filter.names = ["LandscapeCanvas"] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Allow a few seconds for matching entity to be found - self.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) - lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - slice_root_id = lc_matching_entities[0] #Entity with Landscape Canvas component - self.test_success = self.test_success and slice_root_id.IsValid() - if slice_root_id.IsValid(): - self.log("LandscapeCanvas entity found") + # Open a simple level and instantiate LC_BushFlowerBlender.slice + helper.init_idle() + helper.open_level("Physics", "Base") + transform = math.Transform_CreateIdentity() + position = math.Vector3(64.0, 64.0, 32.0) + transform.invoke('SetPosition', position) + test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") + test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), + False) + test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) + Report.critical_result(Tests.slice_instantiated, test_slice.IsValid()) - # Find the BushSpawner entity - search_filter.names = ["BushSpawner"] - spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - spawner_id = spawner_matching_entities[0] #Entity with Vegetation Layer Spawner component - self.test_success = self.test_success and spawner_id.IsValid() - if spawner_id.IsValid(): - self.log("BushSpawner entity found") + # Find root entity in the loaded level + search_filter = entity.SearchFilter() + search_filter.names = ["LandscapeCanvas"] - # Get needed component type ids - distribution_filter_type_id = hydra.get_component_type_id("Vegetation Distribution Filter") - altitude_filter_type_id = hydra.get_component_type_id("Vegetation Altitude Filter") - box_shape_type_id = hydra.get_component_type_id("Box Shape") + # Allow a few seconds for matching entity to be found + helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + slice_root_id = lc_matching_entities[0] #Entity with Landscape Canvas component + Report.critical_result(Tests.lc_entity_found, slice_root_id.IsValid()) - # Verify the BushSpawner entity has a Distribution Filter - has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, - distribution_filter_type_id) - self.test_success = self.test_success and has_distribution_filter - if has_distribution_filter: - self.log("Vegetation Distribution Filter on BushSpawner entity found") + # Find the BushSpawner entity + search_filter.names = ["BushSpawner"] + spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + spawner_id = spawner_matching_entities[0] #Entity with Vegetation Layer Spawner component + Report.critical_result(Tests.spawner_entity_found, spawner_id.IsValid()) - # Open Landscape Canvas and the existing graph - general.open_pane('Landscape Canvas') - open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) - self.test_success = self.test_success and open_graph.IsValid() - if open_graph.IsValid(): - self.log("Graph opened") + # Get needed component type ids + distribution_filter_type_id = hydra.get_component_type_id("Vegetation Distribution Filter") + altitude_filter_type_id = hydra.get_component_type_id("Vegetation Altitude Filter") + box_shape_type_id = hydra.get_component_type_id("Box Shape") - # Verify that Distribution Filter node is present on the graph - spawner_distribution_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, - distribution_filter_type_id) - spawner_distribution_filter_component_id = spawner_distribution_filter_component.GetValue() - distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, - 'GetNodeMatchingEntityComponentInGraph', - open_graph, - spawner_distribution_filter_component_id) - self.test_success = self.test_success and distribution_filter_node is not None - if distribution_filter_node is not None: - self.log("Distribution Filter node found on graph") - else: - self.log("Distribution Filter node not found on graph") + # Verify the BushSpawner entity has a Distribution Filter + has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, + distribution_filter_type_id) + Report.critical_result(Tests.dist_filter_component_found, has_distribution_filter) - # Add a Vegetation Altitude Filter component to the BushSpawner entity, and verify the node is added to the graph - spawner_altitude_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, - altitude_filter_type_id) - spawner_altitude_filter_component_id = spawner_altitude_filter_component.GetValue() - editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', spawner_id, altitude_filter_type_id) - has_altitude_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, - altitude_filter_type_id) - altitude_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetNodeMatchingEntityComponentInGraph', - open_graph, spawner_altitude_filter_component_id) - self.test_success = self.test_success and has_altitude_filter and altitude_filter_node is not None - if has_altitude_filter: - self.log("Vegetation Altitude Filter on BushSpawner entity found") + # Open Landscape Canvas and the existing graph + general.open_pane('Landscape Canvas') + open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + Report.critical_result(Tests.existing_graph_opened, open_graph.IsValid()) - if altitude_filter_node is not None: - self.log("Altitude Filter node found on graph") - else: - self.log("Altitude Filter node not found on graph") + # Verify that Distribution Filter node is present on the graph + spawner_distribution_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, + distribution_filter_type_id) + spawner_distribution_filter_component_id = spawner_distribution_filter_component.GetValue() + distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, + 'GetNodeMatchingEntityComponentInGraph', + open_graph, + spawner_distribution_filter_component_id) + Report.critical_result(Tests.dist_filter_node_found, distribution_filter_node is not None) - # Remove the Distribution Filter - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [spawner_distribution_filter_component_id]) - general.idle_wait(1.0) + # Add a Vegetation Altitude Filter component to the BushSpawner entity, and verify the node is added to the graph + spawner_altitude_filter_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, + altitude_filter_type_id) + spawner_altitude_filter_component_id = spawner_altitude_filter_component.GetValue() + editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', spawner_id, altitude_filter_type_id) + has_altitude_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, + altitude_filter_type_id) + altitude_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetNodeMatchingEntityComponentInGraph', + open_graph, spawner_altitude_filter_component_id) + Report.result(Tests.dist_filter_component_found, has_altitude_filter) + Report.result(Tests.dist_filter_node_found, altitude_filter_node is not None) - # Verify the Distribution Filter was successfully removed from entity and the node was likewise removed - has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, - distribution_filter_type_id) - self.test_success = self.test_success and not has_distribution_filter - if not has_distribution_filter: - self.log("Vegetation Distribution Filter removed from BushSpawner entity") + # Remove the Distribution Filter + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [spawner_distribution_filter_component_id]) + general.idle_wait(1.0) - distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, - 'GetAllNodesMatchingEntityComponent', - spawner_distribution_filter_component_id) - self.test_success = self.test_success and not distribution_filter_node - if distribution_filter_node: - self.log("Distribution Filter node is still present on the graph") - else: - self.log("Distribution Filter node was removed from the graph") + # Verify the Distribution Filter was successfully removed from entity and the node was likewise removed + has_distribution_filter = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', spawner_id, + distribution_filter_type_id) + Report.result(Tests.dist_filter_component_removed, not has_distribution_filter) - # Add a new child entity of BushSpawner entity - box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', spawner_id) - if editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', box_id) == spawner_id: - self.log("New entity successfully added as a child of the BushSpawner entity") - else: - self.log("New entity added with an unexpected parent") + distribution_filter_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, + 'GetAllNodesMatchingEntityComponent', + spawner_distribution_filter_component_id) + Report.result(Tests.dist_filter_node_removed, not distribution_filter_node) - # Add a Box Shape component to the new entity and verify it was properly added - editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', box_id, box_shape_type_id) - has_box_shape = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', box_id, - box_shape_type_id) - self.test_success = self.test_success and has_box_shape - if has_box_shape: - self.log("Box Shape on Box entity found") + # Add a new child entity of BushSpawner entity + box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', spawner_id) + Report.result(Tests.child_entity_added, editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', box_id) == + spawner_id) - # Verify the Box Shape node appear on the graph - box_shape_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', box_id, - box_shape_type_id) + # Add a Box Shape component to the new entity and verify it was properly added + editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', box_id, box_shape_type_id) + has_box_shape = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', box_id, + box_shape_type_id) + Report.result(Tests.box_shape_component_found, has_box_shape) - box_shape_component_id = box_shape_component.GetValue() - box_shape_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', - box_shape_component_id) - self.test_success = self.test_success and box_shape_node is not None - if box_shape_node is not None: - self.log("Box Shape node found on graph") - else: - self.log("Box Shape node not found on graph") + # Verify the Box Shape node appears on the graph + box_shape_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', box_id, + box_shape_type_id) + + box_shape_component_id = box_shape_component.GetValue() + box_shape_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', + box_shape_component_id) + Report.result(Tests.box_shape_node_found, box_shape_node is not None) -test = TestComponentUpdatesUpdateGraph() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ComponentUpdates_UpdateGraph) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py new file mode 100644 index 0000000000..7f21a26595 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py @@ -0,0 +1,80 @@ +""" +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: + lc_component_added = ( + "Landscape Canvas component successfully added to entity", + "Failed to add Landscape Canvas component to entity" + ) + lc_component_removed = ( + "Landscape Canvas component successfully removed from entity", + "Failed to remove Landscape Canvas component from entity" + ) + + +def Component_AddedRemoved(): + """ + Summary: + This test verifies that the Landscape Canvas component can be added to/removed from an entity. + + Expected Behavior: + Closing a tabbed graph only closes the appropriate graph. + + Test Steps: + 1) Open a simple level + 2) Create a new entity + 3) Add a Landscape Canvas component to the entity + 4) Remove the Landscape Canvas component from the entity + + 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 azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create an Entity at the root of the level + newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) + + # Find the component TypeId for our Landscape Canvas component + landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") + + # Add the Landscape Canvas Component to our Entity + componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [landscape_canvas_type_id]) + components = componentOutcome.GetValue() + landscapeCanvasComponent = components[0] + + # Validate the Landscape Canvas Component exists + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) + Report.result(Tests.lc_component_added, hasComponent) + + # Remove the Landscape Canvas Component + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [landscapeCanvasComponent]) + + # Validate the Landscape Canvas Component is no longer on our Entity + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) + Report.result(Tests.lc_component_removed, not hasComponent) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Component_AddedRemoved) \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py deleted file mode 100755 index 971134becf..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py +++ /dev/null @@ -1,106 +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 -""" - -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID -new_root_entity_id = None - - -class TestCreateNewGraph(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="CreateNewGraph", args=["level"]) - - def on_entity_created(self, parameters): - global new_root_entity_id - new_root_entity_id = parameters[0] - - print("New root entity created") - - def run_test(self): - """ - Summary: - This test verifies that new graphs can be created in Landscape Canvas. - - Expected Behavior: - New graphs can be created, and proper entity is created to hold graph data with a Landscape Canvas component. - - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Ensures the root entity created contains a Landscape Canvas component - - 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 - """ - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - # Open Landscape Canvas tool and verify - general.open_pane("Landscape Canvas") - self.test_success = self.test_success and general.is_pane_visible("Landscape Canvas") - if general.is_pane_visible("Landscape Canvas"): - self.log("Landscape Canvas pane is open") - - # Listen for entity creation notifications so we can check if the entity created - # with the new graph has our Landscape Canvas component automatically added - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback("OnEditorEntityCreated", self.on_entity_created) - - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, "CreateNewGraph", editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") - - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, "ContainsGraph", editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") - - # Check if the entity created when we create a new graph has the - # Landscape Canvas component already added to it - landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") - success = editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_root_entity_id, - landscape_canvas_type_id) - self.test_success = self.test_success and success - if success: - self.log("Root entity has Landscape Canvas component") - - # Close Landscape Canvas tool and verify - general.close_pane("Landscape Canvas") - self.test_success = self.test_success and not general.is_pane_visible("Landscape Canvas") - if not general.is_pane_visible("Landscape Canvas"): - self.log("Landscape Canvas pane is closed") - - # Stop listening for entity creation notifications - handler.disconnect() - - -test = TestCreateNewGraph() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py index b2b9e63a56..417e093567 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py @@ -5,131 +5,132 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestDisabledNodeDuplication(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="DisabledNodeDuplication", args=["level"]) +def Edit_DisabledNodeDuplication(): + """ + Summary: + This test verifies Editor stability after duplicating disabled Landscape Canvas nodes. - def run_test(self): - """ - Summary: - This test verifies Editor stability after duplicating disabled Landscape Canvas nodes. + Expected Behavior: + Editor remains stable and free of crashes. - Expected Behavior: - Editor remains stable and free of crashes. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Create several new nodes, disable the nodes via disabling/deleting components, and duplicate the nodes - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Create several new nodes, disable the nodes via disabling/deleting components, and duplicate the nodes + 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. - 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 + """ - :return: None - """ - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Listen for entity creation notifications so when we add a new node - # we can access the corresponding Entity that was created so that we - # can disable/remove components on that Entity - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Mapping of our Landscape Canvas nodes with corresponding dependent components - # that we can disable/remove to reproduce the crash - nodes = { - 'SpawnerAreaNode': 'Vegetation Asset List', - 'MeshBlockerAreaNode': 'Mesh', - 'BlockerAreaNode': 'Vegetation Reference Shape', - 'FastNoiseGradientNode': 'Gradient Transform Modifier', - 'ImageGradientNode': 'Gradient Transform Modifier', - 'PerlinNoiseGradientNode': 'Gradient Transform Modifier', - 'RandomNoiseGradientNode': 'Gradient Transform Modifier' - } + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = list(set(nodes.values())) # Convert to set then back to list to remove any duplicates - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Iterate through creating our nodes and then disabling/deleting required components - # and then duplicating the node to reproduce the crash - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in nodes: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so when we add a new node + # we can access the corresponding Entity that was created so that we + # can disable/remove components on that Entity + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - dependentComponentName = nodes[nodeName] - componentTypeId = componentTypeIds[dependentComponentName] - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, componentTypeId) - component = componentOutcome.GetValue() + # Mapping of our Landscape Canvas nodes with corresponding dependent components + # that we can disable/remove to reproduce the crash + nodes = { + 'SpawnerAreaNode': 'Vegetation Asset List', + 'MeshBlockerAreaNode': 'Mesh', + 'BlockerAreaNode': 'Vegetation Reference Shape', + 'FastNoiseGradientNode': 'Gradient Transform Modifier', + 'ImageGradientNode': 'Gradient Transform Modifier', + 'PerlinNoiseGradientNode': 'Gradient Transform Modifier', + 'RandomNoiseGradientNode': 'Gradient Transform Modifier' + } - # First make sure we can duplicate a node with a dependent component that is disabled - editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [component]) - general.idle_wait(1.0) - graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix - self.log("{node} duplicated with disabled component".format(node=nodeName)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = list(set(nodes.values())) # Convert to set then back to list to remove any duplicates + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Then, make sure we can duplicate the node with a dependent component that is deleted - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component]) - general.idle_wait(1.0) - graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix - self.log("{node} duplicated with deleted component".format(node=nodeName)) + # Iterate through creating our nodes and then disabling/deleting required components + # and then duplicating the node to reproduce the crash + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in nodes: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - x += 40.0 - y += 40.0 + dependentComponentName = nodes[nodeName] + componentTypeId = componentTypeIds[dependentComponentName] + componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, componentTypeId) + component = componentOutcome.GetValue() - # Stop listening for entity creation notifications - handler.disconnect() + # First make sure we can duplicate a node with a dependent component that is disabled + editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [component]) + helper.wait_for_condition(lambda: not editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', + [component]), 1.0) + graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix + Report.info("{node} duplicated with disabled component".format(node=nodeName)) + + # Then, make sure we can duplicate the node with a dependent component that is deleted + editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [component]) + helper.wait_for_condition(lambda: not editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', + componentTypeIds[dependentComponentName]), 1.0) + graph.SceneRequestBus(bus.Event, 'DuplicateSelection', newGraphId) # This duplication would cause a crash without the fix + Report.info("{node} duplicated with deleted component".format(node=nodeName)) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestDisabledNodeDuplication() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Edit_DisabledNodeDuplication) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py index a651567f85..a26e16755f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py @@ -5,133 +5,134 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.math as math -import azlmbr.slice as slice -import azlmbr.paths +class Tests: + slice_spawned = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + lc_entity_found = ( + "Landscape Canvas entity found", + "Failed to find Landscape Canvas entity" + ) + spawner_entity_found = ( + "Spawner entity found", + "Failed to find Spawner entity" + ) + graph_opened = ( + "Graph successfully opened", + "Graph failed to open" + ) + spawner_node_found = ( + "Vegetation Layer Spawner node found on graph", + "Failed to find Vegetation Layer Spawner node on graph" + ) + spawner_node_removed = ( + "Vegetation Layer Spawner node was successfully removed", + "Failed to remove Vegetation Layer Spawner node" + ) +def Edit_UndoNodeDelete_SliceEntity(): + """ + Summary: + This test verifies Editor stability after undoing the deletion of nodes on a slice entity. -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper + Expected Behavior: + Editor remains stable and free of crashes. + + Test Steps: + 1) Open a simple level + 2) Instantiate a slice with a Landscape Canvas setup + 3) Find a specific node on the graph, and delete it + 4) Restore the node with Undo + + 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 azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.math as math + import azlmbr.slice as slice + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Instantiate slice + transform = math.Transform_CreateIdentity() + position = math.Vector3(64.0, 64.0, 32.0) + transform.invoke('SetPosition', position) + test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") + test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), + False) + test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) + Report.result(Tests.slice_spawned, test_slice.IsValid()) + + # Find root entity in the loaded level + search_filter = entity.SearchFilter() + search_filter.names = ["LandscapeCanvas"] + + # Allow a few seconds for matching entity to be found + helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + slice_root_id = lc_matching_entities[0] # Entity with Landscape Canvas component + Report.result(Tests.lc_entity_found, slice_root_id.IsValid()) + + # Find the BushSpawner entity + search_filter.names = ["BushSpawner"] + spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) + spawner_id = spawner_matching_entities[0] # Entity with Vegetation Layer Spawner component + Report.result(Tests.spawner_entity_found, spawner_id.IsValid()) + + # Open Landscape Canvas and the existing graph + general.open_pane('Landscape Canvas') + open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + Report.result(Tests.graph_opened, open_graph.IsValid()) + + # Get needed component type ids + layer_spawner_type_id = hydra.get_component_type_id("Vegetation Layer Spawner") + + # Find the Vegetation Layer Spawner node on the BushSpawner entity + layer_spawner_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, + layer_spawner_type_id) + layer_spawner_component_component_id = layer_spawner_component.GetValue() + layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', + layer_spawner_component_component_id) + Report.result(Tests.spawner_node_found, layer_spawner_node is not None) + + # Remove the Layer Spawner node + graph.GraphControllerRequestBus(bus.Event, "RemoveNode", open_graph, layer_spawner_node[0]) + + # Verify node was removed + layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', + layer_spawner_component_component_id) + Report.result(Tests.spawner_node_removed, not layer_spawner_node) + + # Undo the Node deletion. This is required to be executed twice to hit the node removal. + general.undo() + general.undo() + + # self.log a line to the Console to verify the Editor is still active + Report.info("Editor is still responsive") -class TestUndoNodeDeleteSlice(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="UndoNodeDeleteSlice", args=["level"]) +if __name__ == "__main__": - def run_test(self): - """ - Summary: - This test verifies Editor stability after undoing the deletion of nodes on a slice entity. + from editor_python_test_tools.utils import Report + Report.start_test(Edit_UndoNodeDelete_SliceEntity) - Expected Behavior: - Editor remains stable and free of crashes. - - Test Steps: - 1) Create a new level - 2) Instantiate a slice with a Landscape Canvas setup - 3) Find a specific node on the graph, and delete it - 4) Restore the node with Undo - - 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 - """ - # Create a new empty level and instantiate LC_BushFlowerBlender.slice - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - transform = math.Transform_CreateIdentity() - position = math.Vector3(64.0, 64.0, 32.0) - transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - self.test_success = self.test_success and test_slice.IsValid() - if test_slice.IsValid(): - self.log("Slice spawned!") - - # Find root entity in the loaded level - search_filter = entity.SearchFilter() - search_filter.names = ["LandscapeCanvas"] - - # Allow a few seconds for matching entity to be found - self.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, - 5.0) - lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - slice_root_id = lc_matching_entities[0] # Entity with Landscape Canvas component - self.test_success = self.test_success and slice_root_id.IsValid() - if slice_root_id.IsValid(): - self.log("LandscapeCanvas entity found") - - # Find the BushSpawner entity - search_filter.names = ["BushSpawner"] - spawner_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - spawner_id = spawner_matching_entities[0] # Entity with Vegetation Layer Spawner component - self.test_success = self.test_success and spawner_id.IsValid() - if spawner_id.IsValid(): - self.log("BushSpawner entity found") - - # Open Landscape Canvas and the existing graph - general.open_pane('Landscape Canvas') - open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) - self.test_success = self.test_success and open_graph.IsValid() - if open_graph.IsValid(): - self.log("Graph opened") - - # Get needed component type ids - layer_spawner_type_id = hydra.get_component_type_id("Vegetation Layer Spawner") - - # Find the Vegetation Layer Spawner node on the BushSpawner entity - layer_spawner_component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', spawner_id, - layer_spawner_type_id) - layer_spawner_component_component_id = layer_spawner_component.GetValue() - layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', - layer_spawner_component_component_id) - - self.test_success = self.test_success and layer_spawner_node - if layer_spawner_node: - self.log("Vegetation Layer Spawner node found on graph") - else: - self.log("Vegetation Layer Spawner node not found") - - # Remove the Layer Spawner node - graph.GraphControllerRequestBus(bus.Event, "RemoveNode", open_graph, layer_spawner_node[0]) - - # Verify node was removed - layer_spawner_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', - layer_spawner_component_component_id) - - self.test_success = self.test_success and not layer_spawner_node - if not layer_spawner_node: - self.log("Vegetation Layer Spawner node was removed") - else: - self.log("Vegetation Layer Spawner node was not removed") - - # Undo the Node deletion. This is required to be executed twice to hit the node removal. - general.undo() - general.undo() - - # self.log a line to the Console to verify the Editor is still active - self.log("Editor is still responsive") - - -test = TestUndoNodeDeleteSlice() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py index 341e6d3367..c390df7c61 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py @@ -5,190 +5,205 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.entity as entity -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + preview_entity_set = ( + "Perlin Noise Gradient component Preview Entity property set to Box Shape EntityId", + "Unexpected entity set in Perlin Noise Gradient Preview Entity property" + ) + mixer_inbound_gradient_set_a = ( + "Gradient Mixer component Inbound Gradient extendable property set to Perlin Noise Gradient EntityId", + "Unexpected entity set in Gradient Mixer's Inbound Gradient property" + ) + mixer_inbound_gradient_set_b = ( + "Gradient Mixer component Inbound Gradient extendable property set to FastNoise Gradient EntityId", + "Unexpected entity set in Gradient Mixer's Inbound Gradient property" + ) + mixer_operation_a = ( + "Layer 1 Operation is set to Initialize", + "Layer 1 Operation is not set to Initialize as expected" + ) + mixer_operation_b = ( + "Layer 2 Operation is set to Average", + "Layer 2 Operation is not set to Average as expected" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientMixerNodeConstruction(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientMixerNodeConstruction", args=["level"]) +def GradientMixer_NodeConstruction(): + """ + Summary: + This test verifies a Gradient Mixer vegetation setup can be constructed through Landscape Canvas. - def run_test(self): - """ - Summary: - This test verifies a Gradient Mixer vegetation setup can be constructed through Landscape Canvas. + Expected Behavior: + Entities contain all required components and component references after creating nodes and setting connections + on a Landscape Canvas graph. - Expected Behavior: - Entities contain all required components and component references after creating nodes and setting connections - on a Landscape Canvas graph. + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Add all necessary nodes to the graph and set connections to form a Gradient Mixer setup + 4) Verify all components and component references were properly set during graph construction - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Add all necessary nodes to the graph and set connections to form a Gradient Mixer setup - 4) Verify all components and component references were properly set during graph construction + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can verify the component EntityId - # references are set correctly when connecting slots on the nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - positionX = 10.0 - positionY = 10.0 - offsetX = 340.0 - offsetY = 100.0 + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Add a Box Shape node to the graph - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'BoxShapeNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, positionY)) - boxShapeEntityId = newEntityId + # Listen for entity creation notifications so we can verify the component EntityId + # references are set correctly when connecting slots on the nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - positionX += offsetX - positionY += offsetY + positionX = 10.0 + positionY = 10.0 + offsetX = 340.0 + offsetY = 100.0 - # Add a Random Noise Gradient node to the graph - perlinNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'PerlinNoiseGradientNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, perlinNoiseNode, math.Vector2(positionX, positionY)) - perlinNoiseEntityId = newEntityId + # Add a Box Shape node to the graph + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'BoxShapeNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, positionY)) + boxShapeEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - # Add a FastNoise Gradient node to the graph - fastNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'FastNoiseGradientNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, fastNoiseNode, math.Vector2(positionX, positionY)) - fastNoiseEntityId = newEntityId + # Add a Random Noise Gradient node to the graph + perlinNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'PerlinNoiseGradientNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, perlinNoiseNode, math.Vector2(positionX, positionY)) + perlinNoiseEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - # Add a Gradient Mixer node to the graph - gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, - 'GradientMixerNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, positionY)) - gradientMixerEntityId = newEntityId + # Add a FastNoise Gradient node to the graph + fastNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'FastNoiseGradientNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, fastNoiseNode, math.Vector2(positionX, positionY)) + fastNoiseEntityId = newEntityId - boundsSlotId = graph.GraphModelSlotId('Bounds') - previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') - inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') - outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') - inboundGradientSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, gradientMixerNode, - 'InboundGradient') + positionX += offsetX + positionY += offsetY - # Connect slots on our nodes to construct a Gradient Mixer hierarchy - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - perlinNoiseNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - fastNoiseNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - gradientMixerNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, perlinNoiseNode, outboundGradientSlotId, - gradientMixerNode, inboundGradientSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, fastNoiseNode, outboundGradientSlotId, - gradientMixerNode, inboundGradientSlotId2) + # Add a Gradient Mixer node to the graph + gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, + 'GradientMixerNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, positionY)) + gradientMixerEntityId = newEntityId - # Delay to allow all the underlying component properties to be updated after the slot connections are made - general.idle_wait(1.0) + boundsSlotId = graph.GraphModelSlotId('Bounds') + previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') + inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') + outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') + inboundGradientSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, gradientMixerNode, + 'InboundGradient') - # Get component info - gradientMixerTypeId = hydra.get_component_type_id("Gradient Mixer") - perlinNoiseTypeId = hydra.get_component_type_id("Perlin Noise Gradient") - gradientMixerOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', gradientMixerEntityId, - gradientMixerTypeId) - gradientMixerComponent = gradientMixerOutcome.GetValue() - perlinNoiseOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', perlinNoiseEntityId, - perlinNoiseTypeId) - perlinNoiseComponent = perlinNoiseOutcome.GetValue() + # Connect slots on our nodes to construct a Gradient Mixer hierarchy + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + perlinNoiseNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + fastNoiseNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + gradientMixerNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, perlinNoiseNode, outboundGradientSlotId, + gradientMixerNode, inboundGradientSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, fastNoiseNode, outboundGradientSlotId, + gradientMixerNode, inboundGradientSlotId2) - # Verify the Preview EntityId property on our Perlin Noise Gradient component has been set to our Box Shape's EntityId - previewEntityId = hydra.get_component_property_value(perlinNoiseComponent, 'Preview Settings|Pin Preview to Shape') - self.test_success = self.test_success and previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId) - if previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId): - self.log("Perlin Noise Gradient component Preview Entity property set to Box Shape EntityId") + # Delay to allow all the underlying component properties to be updated after the slot connections are made + general.idle_wait(1.0) - # Verify the 1st Inbound Gradient EntityId property on our Gradient Mixer component has been set to our Perlin Noise - # Gradient's EntityId - inboundGradientEntityId = hydra.get_component_property_value(gradientMixerComponent, - 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') - self.test_success = self.test_success and inboundGradientEntityId and perlinNoiseEntityId.invoke("Equal", inboundGradientEntityId) - if inboundGradientEntityId and perlinNoiseEntityId.invoke("Equal", inboundGradientEntityId): - self.log("Gradient Mixer component Inbound Gradient extendable property set to Perlin Noise Gradient EntityId") + # Get component info + gradientMixerTypeId = hydra.get_component_type_id("Gradient Mixer") + perlinNoiseTypeId = hydra.get_component_type_id("Perlin Noise Gradient") + gradientMixerOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', gradientMixerEntityId, + gradientMixerTypeId) + gradientMixerComponent = gradientMixerOutcome.GetValue() + perlinNoiseOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', perlinNoiseEntityId, + perlinNoiseTypeId) + perlinNoiseComponent = perlinNoiseOutcome.GetValue() - # Verify the 2nd Inbound Gradient EntityId property on our Gradient Mixer component has been set to our FastNoise - # Gradient Modifier's EntityId - inboundGradientEntityId2 = hydra.get_component_property_value(gradientMixerComponent, - 'Configuration|Layers|[1]|Gradient|Gradient Entity Id') - self.test_success = self.test_success and inboundGradientEntityId2 and fastNoiseEntityId.invoke("Equal", inboundGradientEntityId2) - if inboundGradientEntityId2 and fastNoiseEntityId.invoke("Equal", inboundGradientEntityId2): - self.log("Gradient Mixer component Inbound Gradient extendable property set to FastNoise Gradient EntityId") + # Verify the Preview EntityId property on our Perlin Noise Gradient component has been set to our Box Shape's EntityId + previewEntityId = hydra.get_component_property_value(perlinNoiseComponent, 'Preview Settings|Pin Preview to Shape') + Report.result(Tests.preview_entity_set, previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId)) - # Verify that Gradient Mixer Layer Operations are properly set - hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[0]|Operation') - hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[1]|Operation') + # Verify the 1st Inbound Gradient EntityId property on our Gradient Mixer component has been set to our Perlin Noise + # Gradient's EntityId + inboundGradientEntityId = hydra.get_component_property_value(gradientMixerComponent, + 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') + Report.result(Tests.mixer_inbound_gradient_set_a, inboundGradientEntityId and perlinNoiseEntityId.invoke("Equal", inboundGradientEntityId)) - # Stop listening for entity creation notifications - handler.disconnect() + # Verify the 2nd Inbound Gradient EntityId property on our Gradient Mixer component has been set to our FastNoise + # Gradient Modifier's EntityId + inboundGradientEntityId2 = hydra.get_component_property_value(gradientMixerComponent, + 'Configuration|Layers|[1]|Gradient|Gradient Entity Id') + Report.result(Tests.mixer_inbound_gradient_set_b, inboundGradientEntityId2 and fastNoiseEntityId.invoke("Equal", inboundGradientEntityId2)) + + # Verify that Gradient Mixer Layer Operations are properly set + mixer_operation_a = hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[0]|Operation') + mixer_operation_b = hydra.get_component_property_value(gradientMixerComponent, 'Configuration|Layers|[1]|Operation') + Report.result(Tests.mixer_operation_a, mixer_operation_a == 0) + Report.result(Tests.mixer_operation_b, mixer_operation_b == 6) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientMixerNodeConstruction() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientMixer_NodeConstruction) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py index 43d39602be..c3952fe34b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py @@ -5,132 +5,134 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientModifierNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityCreate", args=["level"]) +def GradientModifierNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging Gradient Modifier nodes to graph area. - Expected Behavior: - New entities are created when dragging Gradient Modifier nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient modifier nodes has the appropriate Gradient Modifier Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Gradient modifier mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradientModifiers = { - 'DitherGradientModifierNode': 'Dither Gradient Modifier', - 'GradientMixerNode': 'Gradient Mixer', - 'InvertGradientModifierNode': 'Invert Gradient Modifier', - 'LevelsGradientModifierNode': 'Levels Gradient Modifier', - 'PosterizeGradientModifierNode': 'Posterize Gradient Modifier', - 'SmoothStepGradientModifierNode': 'Smooth-Step Gradient Modifier', - 'ThresholdGradientModifierNode': 'Threshold Gradient Modifier' - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in gradientModifiers: - componentNames.append(gradientModifiers[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient modifier nodes has the appropriate Gradient Modifier Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for all the gradients modifiers we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradientModifiers: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient modifier mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradientModifiers = { + 'DitherGradientModifierNode': 'Dither Gradient Modifier', + 'GradientMixerNode': 'Gradient Mixer', + 'InvertGradientModifierNode': 'Invert Gradient Modifier', + 'LevelsGradientModifierNode': 'Levels Gradient Modifier', + 'PosterizeGradientModifierNode': 'Posterize Gradient Modifier', + 'SmoothStepGradientModifierNode': 'Smooth-Step Gradient Modifier', + 'ThresholdGradientModifierNode': 'Threshold Gradient Modifier' + } - gradientComponent = gradientModifiers[nodeName] - componentTypeId = componentTypeIds[gradientComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, - component=gradientComponent)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in gradientModifiers: + componentNames.append(gradientModifiers[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - x += 40.0 - y += 40.0 + # Create nodes for all the gradients modifiers we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradientModifiers: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + gradientComponent = gradientModifiers[nodeName] + componentTypeId = componentTypeIds[gradientComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + Report.info(f"Node: {nodeName} | Component: {gradientComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientModifierNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientModifierNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py index f7b4dcf557..d7789a21fb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py @@ -5,126 +5,129 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestGradientModifierNodeEntityDelete(EditorTestHelper): +def GradientModifierNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when Gradient Modifier nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when Gradient Modifier nodes are deleted from a graph. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - :return: None - """ - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Vegetation Area mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradientModifiers = [ - 'DitherGradientModifierNode', - 'GradientMixerNode', - 'InvertGradientModifierNode', - 'LevelsGradientModifierNode', - 'PosterizeGradientModifierNode', - 'SmoothStepGradientModifierNode', - 'ThresholdGradientModifierNode' - ] + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradientModifiers: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + # Vegetation Area mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradientModifiers = [ + 'DitherGradientModifierNode', + 'GradientMixerNode', + 'InvertGradientModifierNode', + 'LevelsGradientModifierNode', + 'PosterizeGradientModifierNode', + 'SmoothStepGradientModifierNode', + 'ThresholdGradientModifierNode' + ] - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradientModifiers: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientModifierNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientModifierNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py index 96eac887cd..c04f9f05f6 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py @@ -5,141 +5,143 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + dependencies_added = ( + "Node created new Entity with all required components", + "Failed to create node with all required components" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientNodeComponentDependency(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientNodeComponentDependency", args=["level"]) +def GradientNodes_DependentComponentsAdded(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with + proper dependent components. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with - proper dependent components. + Expected Behavior: + All expected component dependencies are met when adding a Gradient Modifier node to a graph. - Expected Behavior: - All expected component dependencies are met when adding a Gradient Modifier node to a graph. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure the proper dependent components are + added - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure the proper dependent components are - added + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding these gradients nodes has the main target Gradient Component - # as well as automatically adding all required dependency components - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Gradient mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradients = { - 'FastNoiseGradientNode': 'FastNoise Gradient', - 'ImageGradientNode': 'Image Gradient', - 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', - 'RandomNoiseGradientNode': 'Random Noise Gradient' - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - commonComponents = [ - 'Gradient Transform Modifier', - 'Vegetation Reference Shape' - ] - componentNames = [] - for name in gradients: - componentNames.append(gradients[name]) - componentNames.extend(commonComponents) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding these gradients nodes has the main target Gradient Component + # as well as automatically adding all required dependency components + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for the gradients that have additional required dependencies and check if - # the Entity created by adding the node has the appropriate Component and required - # Gradient Transform Modifier and Vegetation Reference Shape components added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradients: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradients = { + 'FastNoiseGradientNode': 'FastNoise Gradient', + 'ImageGradientNode': 'Image Gradient', + 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', + 'RandomNoiseGradientNode': 'Random Noise Gradient' + } - gradientComponent = gradients[nodeName] - components = [gradientComponent] + commonComponents - success = False - for component in components: - componentTypeId = componentTypeIds[component] - success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and success - if not success: - break + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + commonComponents = [ + 'Gradient Transform Modifier', + 'Vegetation Reference Shape' + ] + componentNames = [] + for name in gradients: + componentNames.append(gradients[name]) + componentNames.extend(commonComponents) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - if success: - self.log("{node} created new Entity with all required components".format(node=nodeName)) + # Create nodes for the gradients that have additional required dependencies and check if + # the Entity created by adding the node has the appropriate Component and required + # Gradient Transform Modifier and Vegetation Reference Shape components added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradients: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - x += 40.0 - y += 40.0 + gradientComponent = gradients[nodeName] + components = [gradientComponent] + commonComponents + success = False + for component in components: + componentTypeId = componentTypeIds[component] + success = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) + if not success: + break + Report.info(nodeName) + Report.result(Tests.dependencies_added, success) - # Stop listening for entity creation notifications - handler.disconnect() + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeComponentDependency() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientNodes_DependentComponentsAdded) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py index a484de8d2a..d5595e342c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py @@ -5,130 +5,134 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os, sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestGradientNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityCreate", args=["level"]) +def GradientNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging Gradient nodes to graph area. - Expected Behavior: - New entities are created when dragging Gradient nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Gradient mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradients = { - 'AltitudeGradientNode': 'Altitude Gradient', - 'ConstantGradientNode': 'Constant Gradient', - 'FastNoiseGradientNode': 'FastNoise Gradient', - 'ImageGradientNode': 'Image Gradient', - 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', - 'RandomNoiseGradientNode': 'Random Noise Gradient', - 'ShapeAreaFalloffGradientNode': 'Shape Falloff Gradient', - 'SlopeGradientNode': 'Slope Gradient', - 'SurfaceMaskGradientNode': 'Surface Mask Gradient', - } + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in gradients: - componentNames.append(gradients[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradients: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradients = { + 'AltitudeGradientNode': 'Altitude Gradient', + 'ConstantGradientNode': 'Constant Gradient', + 'FastNoiseGradientNode': 'FastNoise Gradient', + 'ImageGradientNode': 'Image Gradient', + 'PerlinNoiseGradientNode': 'Perlin Noise Gradient', + 'RandomNoiseGradientNode': 'Random Noise Gradient', + 'ShapeAreaFalloffGradientNode': 'Shape Falloff Gradient', + 'SlopeGradientNode': 'Slope Gradient', + 'SurfaceMaskGradientNode': 'Surface Mask Gradient', + } - gradientComponent = gradients[nodeName] - componentTypeId = componentTypeIds[gradientComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, component=gradientComponent)) + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in gradients: + componentNames.append(gradients[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - x += 40.0 - y += 40.0 + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradients: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Stop listening for entity creation notifications - handler.disconnect() + gradientComponent = gradients[nodeName] + componentTypeId = componentTypeIds[gradientComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) + Report.info(f"Node: {nodeName} | Component: {gradientComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py index 2e289ff41b..e5bfbfc7f1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py @@ -5,129 +5,131 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestGradientNodeEntityDelete(EditorTestHelper): +def GradientNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when Gradient nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when Gradient nodes are deleted from a graph. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Listen for entity creation notifications so we can check if the entity created - # from adding gradient nodes has the appropriate Gradient Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Gradient mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - gradients = [ - 'AltitudeGradientNode', - 'ConstantGradientNode', - 'FastNoiseGradientNode', - 'ImageGradientNode', - 'PerlinNoiseGradientNode', - 'RandomNoiseGradientNode', - 'ShapeAreaFalloffGradientNode', - 'SlopeGradientNode', - 'SurfaceMaskGradientNode', - ] + # Listen for entity creation notifications so we can check if the entity created + # from adding gradient nodes has the appropriate Gradient Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - # Create nodes for all the gradients we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in gradients: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Gradient mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + gradients = [ + 'AltitudeGradientNode', + 'ConstantGradientNode', + 'FastNoiseGradientNode', + 'ImageGradientNode', + 'PerlinNoiseGradientNode', + 'RandomNoiseGradientNode', + 'ShapeAreaFalloffGradientNode', + 'SlopeGradientNode', + 'SurfaceMaskGradientNode', + ] - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + # Create nodes for all the gradients we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in gradients: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) - # Stop listening for entity creation notifications - handler.disconnect() + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGradientNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GradientNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py index 0ad1549b60..0f83688206 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py @@ -5,100 +5,99 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + graph_closed = ( + "Graph closed on entity delete", + "Graph is still open after entity delete" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newRootEntityId = None -class TestGraphClosedOnEntityDelete(EditorTestHelper): +def GraphClosed_OnEntityDelete(): + """ + Summary: + This test verifies that Landscape Canvas graphs are auto-closed when the corresponding entity is deleted. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphClosedOnEntityDelete", args=["level"]) + Expected Behavior: + When a Landscape Canvas root entity is deleted, the corresponding graph automatically closes. - def run_test(self): - """ - Summary: - This test verifies that Landscape Canvas graphs are auto-closed when the corresponding entity is deleted. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Delete the automatically created entity + 4) Verify the open graph is closed - Expected Behavior: - When a Landscape Canvas root entity is deleted, the corresponding graph automatically closes. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Delete the automatically created entity - 4) Verify the open graph is closed + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global newRootEntityId - newRootEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global newRootEntityId + newRootEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Listen for entity creation notifications so we can store the top-level Entity created - # when a new graph is created, and then delete it to test if the graph is closed - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Create a new graph in Landscape Canvas and verify - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and graphIsOpen - if graphIsOpen: - self.log("Graph registered with Landscape Canvas") + # Listen for entity creation notifications so we can store the top-level Entity created + # when a new graph is created, and then delete it to test if the graph is closed + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Delete the top-level Entity created by the new graph - editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', newRootEntityId) + # Create a new graph in Landscape Canvas and verify + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graphIsOpen) - # We need to delay here because the closing of the graph due to Entity deletion - # is actually queued in order to workaround an undo/redo issue - # Alternatively, we could add a notifications bus for AssetEditorRequests - # that could trigger when graphs are opened/closed and then do the check there - general.idle_enable(True) - general.idle_wait(1.0) + # Delete the top-level Entity created by the new graph + editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', newRootEntityId) - # Verify that the corresponding graph is no longer open - graphIsClosed = not graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and graphIsClosed - if graphIsClosed: - self.log("The graph is no longer open after deleting the Entity") + # We need to delay here because the closing of the graph due to Entity deletion + # is actually queued in order to workaround an undo/redo issue + # Alternatively, we could add a notifications bus for AssetEditorRequests + # that could trigger when graphs are opened/closed and then do the check there + general.idle_enable(True) + general.idle_wait(1.0) - # Stop listening for entity creation notifications - handler.disconnect() + # Verify that the corresponding graph is no longer open + graphIsClosed = not graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_closed, graphIsClosed) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestGraphClosedOnEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphClosed_OnEntityDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py index 374f26d3a4..67c2ec6908 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py @@ -5,82 +5,82 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + graph_closed = ( + "Graph closed on level change", + "Graph is still open after level change" + ) -class TestGraphClosedOnLevelChange(EditorTestHelper): +def GraphClosed_OnLevelChange(): + """ + Summary: + This test verifies that Landscape Canvas graphs are auto-closed when the currently open level changes. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphClosedOnLevelChange", args=["level"]) + Expected Behavior: + When a new level is loaded in the Editor, open Landscape Canvas graphs are automatically closed. - def run_test(self): - """ - Summary: - This test verifies that Landscape Canvas graphs are auto-closed when the currently open level changes. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Open a different level + 4) Verify the open graph is closed - Expected Behavior: - When a new level is loaded in the Editor, open Landscape Canvas graphs are automatically closed. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Open a different level - 4) Verify the open graph is closed + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general - :return: None - """ - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and graphIsOpen - if graphIsOpen: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Open a different level, which should close any open Landscape Canvas graphs - general.open_level_no_prompt('WhiteBox/EmptyLevel') + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Make sure the graph we created is now closed - graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and not graphIsOpen - if not graphIsOpen: - self.log("Graph is no longer open in Landscape Canvas") + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) + + # Open a different level, which should close any open Landscape Canvas graphs + general.open_level_no_prompt('WhiteBox/EmptyLevel') + + # Make sure the graph we created is now closed + graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_closed, not graphIsOpen) -test = TestGraphClosedOnLevelChange() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphClosed_OnLevelChange) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py index f8b0cfdb44..83762e0afb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py @@ -5,95 +5,93 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor.graph as graph -import azlmbr.legacy.general as general -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_open = ( + "Graph is open in Landscape Canvas", + "Graph is not open in Landscape Canvas" + ) + tabbed_graph_closed = ( + "Tabbed graph closed independently", + "Closing tabbed graph resulted in unexpected graphs closing" + ) -class TestGraphClosedTabbedGraph(EditorTestHelper): +def GraphClosed_TabbedGraphClosesIndependently(): + """ + Summary: + This test verifies that Landscape Canvas tabbed graphs can be independently closed. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphClosedTabbedGraph", args=["level"]) + Expected Behavior: + Closing a tabbed graph only closes the appropriate graph. - def run_test(self): - """ - Summary: - This test verifies that Landscape Canvas tabbed graphs can be independently closed. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create several new graphs + 3) Close one of the open graphs + 4) Ensure the graph properly closed, and other open graphs remain open - Expected Behavior: - Closing a tabbed graph only closes the appropriate graph. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create several new graphs - 3) Close one of the open graphs - 4) Ensure the graph properly closed, and other open graphs remain open + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editor_id = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def create_new_graph(): + new_graph_id = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editor_id) + return new_graph_id - # Create 3 new graphs in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + def is_graph_open(graph_id): + graph_open = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editor_id, graph_id) + return graph_open - newGraphId2 = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId2 - if newGraphId2: - self.log("2nd new graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - newGraphId3 = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId3 - if newGraphId3: - self.log("3rd new graph created") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Make sure the graphs we created are open in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - success2 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId2) - success3 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId3) - self.test_success = self.test_success and success and success2 and success3 - if success and success2 and success3: - self.log("Graphs registered with Landscape Canvas") + # Create 3 new graphs in Landscape Canvas and make sure the graphs we created are open in Landscape Canvas + graph1 = create_new_graph() + Report.result(Tests.new_graph_created, graph1 is not None) + Report.result(Tests.graph_open, is_graph_open(graph1)) - # Close a single graph and verify it was properly closed and other graphs remain open - success4 = graph.AssetEditorRequestBus(bus.Event, 'CloseGraph', editorId, newGraphId2) - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - success2 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId2) - success3 = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId3) - self.test_success = self.test_success and success and success3 and success4 and not success2 - if success and success3 and success4 and not success2: - self.log("Graph 2 was successfully closed") + graph2 = create_new_graph() + Report.result(Tests.new_graph_created, graph2 is not None) + Report.result(Tests.graph_open, is_graph_open(graph2)) + + graph3 = create_new_graph() + Report.result(Tests.new_graph_created, graph3 is not None) + Report.result(Tests.graph_open, is_graph_open(graph3)) + + # Close a single graph and verify it was properly closed and other graphs remain open + graph.AssetEditorRequestBus(bus.Event, 'CloseGraph', editor_id, graph2) + Report.result(Tests.tabbed_graph_closed, not is_graph_open(graph2) and is_graph_open(graph1) and + is_graph_open(graph3)) -test = TestGraphClosedTabbedGraph() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphClosed_TabbedGraphClosesIndependently) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py index cc7c2ca7dd..c489c738d5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py @@ -5,155 +5,151 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.math as math -import azlmbr.slice as slice -import azlmbr.paths - -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import automatedtesting_shared.landscape_canvas_utils as lc +class Tests: + slice_instantiated = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + existing_graph_opened = ( + "Opened existing graph from slice", + "Failed to open existing graph" + ) + node_removed = ( + "Rotation Modifier node was removed", + "Failed to remove Rotation Modifier node" + ) + component_removed = ( + "Rotation Modifier component was removed from entity", + "Rotation Modifier component is still present on entity" + ) + entity_deleted = ( + "BushSpawner entity was deleted", + "Failed to delete BushSpawner entity" + ) + entity_reference_updated = ( + "Gradient Entity Id reference was properly updated", + "Gradient Entity Id reference was not updated properly" + ) -class TestGraphUpdatesUpdateComponents(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="GraphUpdatesUpdateComponents", args=["level"]) +def GraphUpdates_UpdateComponent(): + """ + Summary: + This test verifies that components are properly updated as nodes are added/removed/updated. - def run_test(self): - """ - Summary: - This test verifies that components are properly updated as nodes are added/removed/updated. + Expected Behavior: + Landscape Canvas node CRUD properly updates component entities. - Expected Behavior: - Landscape Canvas node CRUD properly updates component entities. + Test Steps: + 1. Open Level. + 2. Open the graph on LC_BushFlowerBlender.slice + 3. Find the Rotation Modifier node on the BushSpawner entity + 4. Delete the Rotation Modifier node + 5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity + 6. Delete the Vegetation Layer Spawner node from the graph + 7. Ensure BushSpawner entity is deleted + 8. Change connection from second Rotation Modifier node to a different Gradient + 9. Ensure Gradient reference on component is updated - Test Steps: - 1. Open Level. - 2. Open the graph on LC_BushFlowerBlender.slice - 3. Find the Rotation Modifier node on the BushSpawner entity - 4. Delete the Rotation Modifier node - 5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity - 6. Delete the Vegetation Layer Spawner node from the graph - 7. Ensure BushSpawner entity is deleted - 8. Change connection from second Rotation Modifier node to a different Gradient - 9. Ensure Gradient reference on component is updated + 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. - 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 + """ - :return: None - """ - # Create a new empty level and instantiate LC_BushFlowerBlender.slice - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - transform = math.Transform_CreateIdentity() - position = math.Vector3(64.0, 64.0, 32.0) - transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - self.test_success = self.test_success and test_slice.IsValid() - if test_slice.IsValid(): - self.log("Slice spawned!") + import os - # Search for root entity to ensure slice is loaded - search_filter = entity.SearchFilter() - search_filter.names = ["LandscapeCanvas"] - self.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.math as math + import azlmbr.slice as slice - # Find needed entities in the loaded level - slice_root_id = hydra.find_entity_by_name('LandscapeCanvas') - bush_spawner_id = hydra.find_entity_by_name('BushSpawner') - flower_spawner_id = hydra.find_entity_by_name('FlowerSpawner') - inverted_perlin_noise_id = hydra.find_entity_by_name('Invert') + import automatedtesting_shared.landscape_canvas_utils as lc + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Open Landscape Canvas and the existing graph - general.open_pane('Landscape Canvas') - open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) - self.test_success = self.test_success and open_graph_id.IsValid() - if open_graph_id.IsValid(): - self.log('Graph opened') + # Open a simple level and instantiate LC_BushFlowerBlender.slice + helper.init_idle() + helper.open_level("Physics", "Base") + transform = math.Transform_CreateIdentity() + position = math.Vector3(64.0, 64.0, 32.0) + transform.invoke('SetPosition', position) + test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") + test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), + False) + test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) + Report.critical_result(Tests.slice_instantiated, test_slice.IsValid()) - # Find the Rotation Modifier node on the BushSpawner entity - rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) + # Search for root entity to ensure slice is loaded + search_filter = entity.SearchFilter() + search_filter.names = ["LandscapeCanvas"] + helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) - # Remove the Rotation Modifier node - graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, rotation_modifier_node[0]) + # Find needed entities in the loaded level + slice_root_id = hydra.find_entity_by_name('LandscapeCanvas') + bush_spawner_id = hydra.find_entity_by_name('BushSpawner') + flower_spawner_id = hydra.find_entity_by_name('FlowerSpawner') + inverted_perlin_noise_id = hydra.find_entity_by_name('Invert') - # Verify node was removed - rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) - self.test_success = self.test_success and not rotation_modifier_node - if not rotation_modifier_node: - self.log('Rotation Modifier node was removed') - else: - self.log('Rotation Modifier node was not removed') + # Open Landscape Canvas and the existing graph + general.open_pane('Landscape Canvas') + open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + Report.critical_result(Tests.existing_graph_opened, open_graph_id.IsValid()) - # Verify the component was removed from the BushSpawner entity - has_rotation_modifier = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', bush_spawner_id, - hydra.get_component_type_id('Vegetation Rotation Modifier')) - self.test_success = self.test_success and not has_rotation_modifier - if not has_rotation_modifier: - self.log('Rotation Modifier component was removed from entity') - else: - self.log('Rotation Modifier component is still present on entity') + # Find the Rotation Modifier node on the BushSpawner entity + rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) - # Find the Vegetation Layer Spawner node on the BushSpawner entity - layer_spawner_node = lc.find_nodes_matching_entity_component('Vegetation Layer Spawner', bush_spawner_id) + # Remove the Rotation Modifier node + graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, rotation_modifier_node[0]) - # Remove the Vegetation Layer Spawner node and verify the corresponding entity is deleted - graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, layer_spawner_node[0]) - bush_spawner_id = hydra.find_entity_by_name('BushSpawner') - self.test_success = self.test_success and not bush_spawner_id - if not bush_spawner_id: - self.log('BushSpawner entity was deleted') - else: - self.log('Failed to delete BushSpawner entity') + # Verify node was removed + rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) + Report.result(Tests.node_removed, not rotation_modifier_node) - # Connect the FlowerSpawner's Rotation Modifier node to the Invert Gradient Modifier node - rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', flower_spawner_id) - invert_node = lc.find_nodes_matching_entity_component('Invert Gradient Modifier', inverted_perlin_noise_id) + # Verify the component was removed from the BushSpawner entity + has_rotation_modifier = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', bush_spawner_id, + hydra.get_component_type_id('Vegetation Rotation Modifier')) + Report.result(Tests.component_removed, not has_rotation_modifier) - inbound_gradient_z_slot = graph.GraphModelSlotId('InboundGradientZ') - outbound_gradient_slot = graph.GraphModelSlotId('OutboundGradient') - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', open_graph_id, invert_node[0], - outbound_gradient_slot, rotation_modifier_node[0], inbound_gradient_z_slot) + # Find the Vegetation Layer Spawner node on the BushSpawner entity + layer_spawner_node = lc.find_nodes_matching_entity_component('Vegetation Layer Spawner', bush_spawner_id) - general.idle_wait(1.0) # Add a small wait to ensure component property has time to update + # Remove the Vegetation Layer Spawner node and verify the corresponding entity is deleted + graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, layer_spawner_node[0]) + bush_spawner_id = hydra.find_entity_by_name('BushSpawner') + Report.result(Tests.entity_deleted, not bush_spawner_id) - # Verify the Gradient Entity Id reference on the Rotation Modifier component was properly set - rotation_type_id = hydra.get_component_type_id('Vegetation Rotation Modifier') - rotation_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', flower_spawner_id, - rotation_type_id) - rotation_component = rotation_outcome.GetValue() - gradient_reference = hydra.get_component_property_value(rotation_component, - 'Configuration|Rotation Z|Gradient|Gradient Entity Id') - gradient_reference_success = gradient_reference == inverted_perlin_noise_id - self.test_success = self.test_success and gradient_reference_success - if gradient_reference_success: - self.log('Gradient Entity Id reference was properly updated') - else: - self.log(f'Gradient Entity Id was not updated properly: Expected {inverted_perlin_noise_id.ToString()} -- Got ' - f'{gradient_reference.ToString()}.') + # Connect the FlowerSpawner's Rotation Modifier node to the Invert Gradient Modifier node + rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', flower_spawner_id) + invert_node = lc.find_nodes_matching_entity_component('Invert Gradient Modifier', inverted_perlin_noise_id) + + inbound_gradient_z_slot = graph.GraphModelSlotId('InboundGradientZ') + outbound_gradient_slot = graph.GraphModelSlotId('OutboundGradient') + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', open_graph_id, invert_node[0], + outbound_gradient_slot, rotation_modifier_node[0], inbound_gradient_z_slot) + + general.idle_wait(1.0) # Add a small wait to ensure component property has time to update + + # Verify the Gradient Entity Id reference on the Rotation Modifier component was properly set + rotation_type_id = hydra.get_component_type_id('Vegetation Rotation Modifier') + rotation_outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', flower_spawner_id, + rotation_type_id) + rotation_component = rotation_outcome.GetValue() + gradient_reference = hydra.get_component_property_value(rotation_component, + 'Configuration|Rotation Z|Gradient|Gradient Entity Id') + Report.result(Tests.entity_reference_updated, gradient_reference == inverted_perlin_noise_id) -test = TestGraphUpdatesUpdateComponents() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(GraphUpdates_UpdateComponent) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py deleted file mode 100755 index ed6f23ae24..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py +++ /dev/null @@ -1,87 +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 -""" - -import os -import sys - -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.entity as entity -import azlmbr.paths - -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - - -class TestLandscapeCanvasComponentAddedRemoved(EditorTestHelper): - - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LandscapeCanvasComponentAddedRemoved", args=["level"]) - - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas component can be added to/removed from an entity. - - Expected Behavior: - Closing a tabbed graph only closes the appropriate graph. - - Test Steps: - 1) Create a new level - 2) Create a new entity - 3) Add a Landscape Canvas component to the entity - 4) Remove the Landscape Canvas component from the entity - - 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 - """ - - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - - # Create an Entity at the root of the level - newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) - - # Find the component TypeId for our Landscape Canvas component - landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") - - # Add the Landscape Canvas Component to our Entity - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [landscape_canvas_type_id]) - components = componentOutcome.GetValue() - landscapeCanvasComponent = components[0] - - # Validate the Landscape Canvas Component exists - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("Landscape Canvas Component added to Entity") - - # Remove the Landscape Canvas Component - editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [landscapeCanvasComponent]) - - # Validate the Landscape Canvas Component is no longer on our Entity - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, landscape_canvas_type_id) - self.test_success = self.test_success and not hasComponent - if not hasComponent: - self.log("Landscape Canvas Component removed from Entity") - - -test = TestLandscapeCanvasComponentAddedRemoved() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py deleted file mode 100755 index 95da5aa7dd..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py +++ /dev/null @@ -1,82 +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 -""" - -import os -import sys - -import azlmbr.math as math -import azlmbr.paths -import azlmbr.bus as bus -import azlmbr.asset as asset -import azlmbr.slice as slice - -sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests")) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper - - -class TestLandscapeCanvasSliceCreateInstantiate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LandscapeCanvas_SliceCreateInstantiate", args=["level"]) - - def run_test(self): - """ - Summary: - A slice containing the LandscapeCanvas component can be created/instantiated. - - Expected Result: - Slice is created/processed/instantiated successfully and free of errors/warnings. - - Test Steps: - 1) Create a new level - 2) Create a new entity with a Landscape Canvas component - 3) Create a slice of the new entity - 4) Instantiate a new copy of the slice - - 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 - """ - - def path_is_valid_asset(asset_path): - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False) - return asset_id.invoke("IsValid") - - # Create empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) - - # Create entity with LandScape Canvas component - position = math.Vector3(512.0, 512.0, 32.0) - landscape_canvas = hydra.Entity("landscape_canvas_entity") - landscape_canvas.create_entity(position, ["Landscape Canvas"]) - - # Create slice from the created entity - slice_path = os.path.join("slices", "TestSlice.slice") - slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", landscape_canvas.id, slice_path) - - # Verify if slice is created - self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0) - self.log(f"Slice has been created successfully: {path_is_valid_asset(slice_path)}") - - # Instantiate slice - transform = math.Transform_CreateIdentity() - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False) - test_slice = slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform) - self.wait_for_condition(lambda: test_slice.IsValid(), 3.0) - self.log(f"Slice instantiated: {test_slice.IsValid()}") - - -test = TestLandscapeCanvasSliceCreateInstantiate() -test.run() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py index f68bfd91a6..b2bf20411b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py @@ -5,157 +5,160 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.entity as entity -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + blender_first_layer_set = ( + "Spawner entity set as the first layer of the Vegetation Layer Blender component", + "Unexpected entity set as the first layer of the Vegetation Layer Blender component" + ) + blender_second_layer_set = ( + "Blocker entity set as the second layer of the Vegetation Layer Blender component", + "Unexpected entity set as the second layer of the Vegetation Layer Blender component" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestLayerBlenderNodeConstruction(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LayerBlenderNodeConstruction", args=["level"]) +def LayerBlender_NodeConstruction(): + """ + Summary: + This test verifies a Layer Blender vegetation setup can be constructed through Landscape Canvas. - def run_test(self): - """ - Summary: - This test verifies a Layer Blender vegetation setup can be constructed through Landscape Canvas. + Expected Behavior: + Entities contain all required components and component references after creating nodes and setting connections + on a Landscape Canvas graph. - Expected Behavior: - Entities contain all required components and component references after creating nodes and setting connections - on a Landscape Canvas graph. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Add all necessary nodes to the graph and set connections to form a Layer Blender setup + 4) Verify all components and component references were properly set during graph construction - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Add all necessary nodes to the graph and set connections to form a Layer Blender setup - 4) Verify all components and component references were properly set during graph construction + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=1024, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=4096, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Listen for entity creation notifications so we can verify the component EntityId - # references are set correctly when connecting slots on the nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - positionX = 10.0 - positionY = 10.0 - offsetX = 340.0 - offsetY = 100.0 + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Add a Vegetation Layer Spawner node to the graph - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - layerSpawnerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'SpawnerAreaNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerSpawnerNode, math.Vector2(positionX, positionY)) - layerSpawnerEntityId = newEntityId + # Listen for entity creation notifications so we can verify the component EntityId + # references are set correctly when connecting slots on the nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - positionX += offsetX - positionY += offsetY + positionX = 10.0 + positionY = 10.0 + offsetX = 340.0 + offsetY = 100.0 - # Add a Vegetation Layer Blocker node to the graph - layerBlockerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'BlockerAreaNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlockerNode, math.Vector2(positionX, positionY)) - layerBlockerEntityId = newEntityId + # Add a Vegetation Layer Spawner node to the graph + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + layerSpawnerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'SpawnerAreaNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerSpawnerNode, math.Vector2(positionX, positionY)) + layerSpawnerEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - # Add a Vegetation Layer Blender node to the graph - layerBlenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'AreaBlenderNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlenderNode, math.Vector2(positionX, positionY)) - layerBlenderNodeEntityId = newEntityId + # Add a Vegetation Layer Blocker node to the graph + layerBlockerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'BlockerAreaNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlockerNode, math.Vector2(positionX, positionY)) + layerBlockerEntityId = newEntityId - positionX += offsetX - positionY += offsetY + positionX += offsetX + positionY += offsetY - outboundAreaSlotId = graph.GraphModelSlotId('OutboundArea') - inboundAreaSlotId = graph.GraphModelSlotId('InboundArea') - inboundAreaSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, layerBlenderNode, - 'InboundArea') + # Add a Vegetation Layer Blender node to the graph + layerBlenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'AreaBlenderNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, layerBlenderNode, math.Vector2(positionX, positionY)) + layerBlenderNodeEntityId = newEntityId - # Connect slots on our nodes to construct a Vegetation Layer Blender hierarchy - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerSpawnerNode, outboundAreaSlotId, - layerBlenderNode, inboundAreaSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerBlockerNode, outboundAreaSlotId, - layerBlenderNode, inboundAreaSlotId2) + positionX += offsetX + positionY += offsetY - # Delay to allow all the underlying component properties to be updated after the slot connections are made - general.idle_wait(1.0) + outboundAreaSlotId = graph.GraphModelSlotId('OutboundArea') + inboundAreaSlotId = graph.GraphModelSlotId('InboundArea') + inboundAreaSlotId2 = graph.GraphControllerRequestBus(bus.Event, 'ExtendSlot', newGraphId, layerBlenderNode, + 'InboundArea') - # Get component info - layerBlenderTypeId = hydra.get_component_type_id("Vegetation Layer Blender") - vegetationLayerBlenderOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', - layerBlenderNodeEntityId, layerBlenderTypeId) - layerBlenderComponent = vegetationLayerBlenderOutcome.GetValue() + # Connect slots on our nodes to construct a Vegetation Layer Blender hierarchy + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerSpawnerNode, outboundAreaSlotId, + layerBlenderNode, inboundAreaSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, layerBlockerNode, outboundAreaSlotId, + layerBlenderNode, inboundAreaSlotId2) - # Verify the Vegetation Areas properties on our Vegetation Layer Blender component have been set to our area EntityIds - area1EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[0]') - self.test_success = self.test_success and area1EntityId and layerSpawnerEntityId.invoke("Equal", area1EntityId) - if area1EntityId and layerSpawnerEntityId.invoke("Equal", area1EntityId): - self.log("Vegetation Layer Blender component Vegetation Areas[0] property set to Vegetation Layer Spawner EntityId") + # Delay to allow all the underlying component properties to be updated after the slot connections are made + general.idle_wait(1.0) - area2EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[1]') - self.test_success = self.test_success and area2EntityId and layerBlockerEntityId.invoke("Equal", area2EntityId) - if area2EntityId and layerBlockerEntityId.invoke("Equal", area2EntityId): - self.log("Vegetation Layer Blender component Vegetation Areas[1] property set to Vegetation Layer Blocker EntityId") + # Get component info + layerBlenderTypeId = hydra.get_component_type_id("Vegetation Layer Blender") + vegetationLayerBlenderOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', + layerBlenderNodeEntityId, layerBlenderTypeId) + layerBlenderComponent = vegetationLayerBlenderOutcome.GetValue() - # Stop listening for entity creation notifications - handler.disconnect() + # Verify the Vegetation Areas properties on our Vegetation Layer Blender component have been set to our area EntityIds + area1EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[0]') + Report.result(Tests.blender_first_layer_set, area1EntityId and layerSpawnerEntityId.invoke("Equal", area1EntityId)) + + area2EntityId = hydra.get_component_property_value(layerBlenderComponent, 'Configuration|Vegetation Areas|[1]') + Report.result(Tests.blender_second_layer_set, area2EntityId and layerBlockerEntityId.invoke("Equal", area2EntityId)) + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestLayerBlenderNodeConstruction() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(LayerBlender_NodeConstruction) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py index 5b523e0b38..510c404614 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py @@ -5,164 +5,170 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "Expected component is present on entity", + "Expected component was not found on entity" + ) + component_removed = ( + "Expected component was removed from entity", + "Component is unexpectedly still present on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestLayerExtenderNodeComponentEntitySync(EditorTestHelper): +def LayerExtenderNodes_ComponentEntitySync(): + """ + Summary: + This test verifies that all wrapped nodes can be successfully added to/removed from parent nodes. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="LayerExtenderNodeComponentEntitySync", args=["level"]) + Expected Behavior: + All wrapped extender nodes can be added to/removed from appropriate parent nodes. - def run_test(self): - """ - Summary: - This test verifies that all wrapped nodes can be successfully added to/removed from parent nodes. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Add Area Blender and Layer Spawner nodes to the graph, and add/remove each extender node to/from each - Expected Behavior: - All wrapped extender nodes can be added to/removed from appropriate parent nodes. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Add Area Blender and Layer Spawner nodes to the graph, and add/remove each extender node to/from each + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - :return: None - """ + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Listen for entity creation notifications so we can check if the - # proper components are added when we add nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Extender mapping with the key being the node name and the value is the - # expected Component that should be added to the layer Entity for that wrapped node - extenders = { - 'AltitudeFilterNode': 'Vegetation Altitude Filter', - 'DistanceBetweenFilterNode': 'Vegetation Distance Between Filter', - 'DistributionFilterNode': 'Vegetation Distribution Filter', - 'ShapeIntersectionFilterNode': 'Vegetation Shape Intersection Filter', - 'SlopeFilterNode': 'Vegetation Slope Filter', - 'SurfaceMaskDepthFilterNode': 'Vegetation Surface Mask Depth Filter', - 'SurfaceMaskFilterNode': 'Vegetation Surface Mask Filter', - 'PositionModifierNode': 'Vegetation Position Modifier', - 'RotationModifierNode': 'Vegetation Rotation Modifier', - 'ScaleModifierNode': 'Vegetation Scale Modifier', - 'SlopeAlignmentModifierNode': 'Vegetation Slope Alignment Modifier', - 'AssetWeightSelectorNode': 'Vegetation Asset Weight Selector' - } + # Listen for entity creation notifications so we can check if the + # proper components are added when we add nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in extenders: - componentNames.append(extenders[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Extender mapping with the key being the node name and the value is the + # expected Component that should be added to the layer Entity for that wrapped node + extenders = { + 'AltitudeFilterNode': 'Vegetation Altitude Filter', + 'DistanceBetweenFilterNode': 'Vegetation Distance Between Filter', + 'DistributionFilterNode': 'Vegetation Distribution Filter', + 'ShapeIntersectionFilterNode': 'Vegetation Shape Intersection Filter', + 'SlopeFilterNode': 'Vegetation Slope Filter', + 'SurfaceMaskDepthFilterNode': 'Vegetation Surface Mask Depth Filter', + 'SurfaceMaskFilterNode': 'Vegetation Surface Mask Filter', + 'PositionModifierNode': 'Vegetation Position Modifier', + 'RotationModifierNode': 'Vegetation Rotation Modifier', + 'ScaleModifierNode': 'Vegetation Scale Modifier', + 'SlopeAlignmentModifierNode': 'Vegetation Slope Alignment Modifier', + 'AssetWeightSelectorNode': 'Vegetation Asset Weight Selector' + } - areas = [ - 'AreaBlenderNode', - 'SpawnerAreaNode' - ] + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in extenders: + componentNames.append(extenders[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Add/remove all our supported extender nodes to the Layer Areas and check if the appropriate - # Components are added/removed to the wrapper node's Entity - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for areaName in areas: - nodePosition = math.Vector2(x, y) - areaNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, areaName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, areaNode, nodePosition) + areas = [ + 'AreaBlenderNode', + 'SpawnerAreaNode' + ] - success = True - for extenderName in extenders: - # Add the wrapped node for the extender - extenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, - 'CreateNodeForTypeName', newGraph, - extenderName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, extenderNode, nodePosition) - graph.GraphControllerRequestBus(bus.Event, 'WrapNode', newGraphId, areaNode, extenderNode) + # Add/remove all our supported extender nodes to the Layer Areas and check if the appropriate + # Components are added/removed to the wrapper node's Entity + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for areaName in areas: + nodePosition = math.Vector2(x, y) + areaNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, areaName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, areaNode, nodePosition) - # Check that the appropriate Component was added when the extender node was added - extenderComponent = extenders[extenderName] - componentTypeId = componentTypeIds[extenderComponent] - success = success and editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + success = True + for extenderName in extenders: + # Add the wrapped node for the extender + extenderNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, + 'CreateNodeForTypeName', newGraph, + extenderName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, extenderNode, nodePosition) + graph.GraphControllerRequestBus(bus.Event, 'WrapNode', newGraphId, areaNode, extenderNode) + + # Check that the appropriate Component was added when the extender node was added + extenderComponent = extenders[extenderName] + componentTypeId = componentTypeIds[extenderComponent] + success = success and editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + Report.info(f"Component: {extenderComponent}") + Report.result(Tests.component_added, success) + if not success: + break + + # Check that the appropriate Component was removed when the extender node was removed + graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, extenderNode) + success = success and not editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, componentTypeId) - self.test_success = self.test_success and success - if not success: - self.log("{node} failed to add {component} Component".format(node=areaName, - component=extenderComponent)) - break + Report.info(f"Component: {extenderComponent}") + Report.result(Tests.component_removed, success) + if not success: + break - # Check that the appropriate Component was removed when the extender node was removed - graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, extenderNode) - success = success and not editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - self.test_success = self.test_success and success - if not success: - self.log("{node} failed to remove {component} Component".format(node=areaName, - component=extenderComponent)) - break + if success: + Report.info(f"{areaName} successfully added and removed all filters/modifiers/selectors") - if success: - self.log("{node} successfully added and removed all filters/modifiers/selectors".format(node=areaName)) - - # Stop listening for entity creation notifications - handler.disconnect() + # Stop listening for entity creation notifications + handler.disconnect() -test = TestLayerExtenderNodeComponentEntitySync() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(LayerExtenderNodes_ComponentEntitySync) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py new file mode 100644 index 0000000000..d13c5dfa2f --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py @@ -0,0 +1,111 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + lc_component_added = ( + "Root entity created with the Landscape Canvas component", + "Landscape Canvas component was not found on the root entity" + ) + lc_tool_closed = ( + "Landscape Canvas tool closed", + "Failed to close Landscape Canvas tool" + ) + + +new_root_entity_id = None + + +def NewGraph_CreatedSuccessfully(): + """ + Summary: + This test verifies that new graphs can be created in Landscape Canvas. + + Expected Behavior: + New graphs can be created, and proper entity is created to hold graph data with a Landscape Canvas component. + + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Ensures the root entity created contains a Landscape Canvas component + + 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 azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.legacy.general as general + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID + + def on_entity_created(parameters): + global new_root_entity_id + new_root_entity_id = parameters[0] + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Listen for entity creation notifications so we can check if the entity created + # with the new graph has our Landscape Canvas component automatically added + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback("OnEditorEntityCreated", on_entity_created) + + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) + + # Create a new graph in Landscape Canvas + new_graph_id = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, new_graph_id is not None) + + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, new_graph_id) + Report.result(Tests.graph_registered, graph_registered) + + # Check if the entity created when we create a new graph has the + # Landscape Canvas component already added to it + landscape_canvas_type_id = hydra.get_component_type_id("Landscape Canvas") + success = editor.EditorComponentAPIBus(bus.Broadcast, "HasComponentOfType", new_root_entity_id, + landscape_canvas_type_id) + Report.result(Tests.lc_component_added, success) + + # Close Landscape Canvas tool and verify + general.close_pane("Landscape Canvas") + Report.result(Tests.lc_tool_closed, not general.is_pane_visible("Landscape Canvas")) + + # Stop listening for entity creation notifications + handler.disconnect() + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(NewGraph_CreatedSuccessfully) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py index 0c877535a9..93464c7ad3 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py @@ -5,133 +5,136 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + component_added = ( + "New entity created with the expected component", + "Expected component was not found on entity" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestShapeNodeEntityCreate(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityCreate", args=["level"]) +def ShapeNodes_EntityCreatedOnNodeAdd(): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging shape nodes to graph area. - Expected Behavior: - New entities are created when dragging shape nodes to graph area. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created + 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. - 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 + """ - :return: None - """ + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") + # Open an existing simple level - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") + helper.init_idle() + helper.open_level("Physics", "Base") - # Listen for entity creation notifications so we can check if the entity created - # from adding shape nodes has the appropriate Shape Component - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) - # Shape mapping with the key being the node name and the value is the - # expected Component that should be added to the Entity created for the node - shapes = { - 'BoxShapeNode': 'Box Shape', - 'CapsuleShapeNode': 'Capsule Shape', - 'CompoundShapeNode': 'Compound Shape', - 'CylinderShapeNode': 'Cylinder Shape', - 'PolygonPrismShapeNode': 'Polygon Prism Shape', - 'SphereShapeNode': 'Sphere Shape', - 'TubeShapeNode': 'Tube Shape', - 'DiskShapeNode': 'Disk Shape' - } + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) - # Retrieve a mapping of the TypeIds for all the components - # we will be checking for - componentNames = [] - for name in shapes: - componentNames.append(shapes[name]) - componentTypeIds = hydra.get_component_type_id_map(componentNames) + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) - # Create nodes for all the shapes we support and check if the Entity created by - # adding the node has the appropriate Component added automatically to it - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in shapes: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + # Listen for entity creation notifications so we can check if the entity created + # from adding shape nodes has the appropriate Shape Component + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) - shapeComponent = shapes[nodeName] - componentTypeId = componentTypeIds[shapeComponent] - hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, - componentTypeId) - self.test_success = self.test_success and hasComponent - if hasComponent: - self.log("{node} created new Entity with {component} Component".format(node=nodeName, - component=shapeComponent)) + # Shape mapping with the key being the node name and the value is the + # expected Component that should be added to the Entity created for the node + shapes = { + 'BoxShapeNode': 'Box Shape', + 'CapsuleShapeNode': 'Capsule Shape', + 'CompoundShapeNode': 'Compound Shape', + 'CylinderShapeNode': 'Cylinder Shape', + 'PolygonPrismShapeNode': 'Polygon Prism Shape', + 'SphereShapeNode': 'Sphere Shape', + 'TubeShapeNode': 'Tube Shape', + 'DiskShapeNode': 'Disk Shape' + } - x += 40.0 - y += 40.0 + # Retrieve a mapping of the TypeIds for all the components + # we will be checking for + componentNames = [] + for name in shapes: + componentNames.append(shapes[name]) + componentTypeIds = hydra.get_component_type_id_map(componentNames) - # Stop listening for entity creation notifications - handler.disconnect() + # Create nodes for all the shapes we support and check if the Entity created by + # adding the node has the appropriate Component added automatically to it + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in shapes: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + + shapeComponent = shapes[nodeName] + componentTypeId = componentTypeIds[shapeComponent] + hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, + componentTypeId) + Report.info(f"Node: {nodeName} | Component: {shapeComponent}") + Report.result(Tests.component_added, hasComponent) + + x += 40.0 + y += 40.0 + + # Stop listening for entity creation notifications + handler.disconnect() -test = TestShapeNodeEntityCreate() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ShapeNodes_EntityCreatedOnNodeAdd) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py index 2416e05fdf..d2708f643d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py @@ -5,127 +5,129 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + entity_deleted = ( + "Entity was deleted when node was removed", + "Entity was not deleted as expected when node was removed" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID createdEntityId = None deletedEntityId = None -class TestShapeNodeEntityDelete(EditorTestHelper): +def ShapeNodes_EntityRemovedOnNodeDelete(): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityDelete", args=["level"]) + Expected Behavior: + Entities are removed when shape nodes are deleted from a graph. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Test Steps: + 1) Open a simple level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed - Expected Behavior: - Entities are removed when shape nodes are deleted from a graph. + 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. - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created - 4) Delete the nodes, and ensure the newly created entities are removed + :return: None + """ - 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. + import azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math - :return: None - """ + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - def onEntityCreated(parameters): - global createdEntityId - createdEntityId = parameters[0] - - def onEntityDeleted(parameters): - global deletedEntityId - deletedEntityId = parameters[0] + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') - - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") - - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") - - # Listen for entity creation/deletion notifications so we can verify the - # Entity created when adding a new also gets deleted when the node is deleted - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) - - # All of the shape nodes that we support - shapes = [ - 'BoxShapeNode', - 'CapsuleShapeNode', - 'CompoundShapeNode', - 'CylinderShapeNode', - 'PolygonPrismShapeNode', - 'SphereShapeNode', - 'TubeShapeNode', - 'DiskShapeNode' - ] - - # Create nodes for all the shapes we support and check if the Entity is created - # and then deleted when the node is removed - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - x = 10.0 - y = 10.0 - for nodeName in shapes: - nodePosition = math.Vector2(x, y) - node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) - - removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) - - # Verify that the created Entity for this node matches the Entity that gets - # deleted when the node is removed - self.test_success = self.test_success and removed and createdEntityId.invoke("Equal", deletedEntityId) - if removed and createdEntityId.invoke("Equal", deletedEntityId): - self.log("{node} corresponding Entity was deleted when node is removed".format(node=nodeName)) - - # Stop listening for entity creation/deletion notifications - handler.disconnect() + def onEntityCreated(parameters): + global createdEntityId + createdEntityId = parameters[0] + + def onEntityDeleted(parameters): + global deletedEntityId + deletedEntityId = parameters[0] + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) + + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) + + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) + + # Listen for entity creation/deletion notifications so we can verify the + # Entity created when adding a new also gets deleted when the node is deleted + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + handler.add_callback('OnEditorEntityDeleted', onEntityDeleted) + + # All of the shape nodes that we support + shapes = [ + 'BoxShapeNode', + 'CapsuleShapeNode', + 'CompoundShapeNode', + 'CylinderShapeNode', + 'PolygonPrismShapeNode', + 'SphereShapeNode', + 'TubeShapeNode', + 'DiskShapeNode' + ] + + # Create nodes for all the shapes we support and check if the Entity is created + # and then deleted when the node is removed + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + x = 10.0 + y = 10.0 + for nodeName in shapes: + nodePosition = math.Vector2(x, y) + node = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', newGraph, nodeName) + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, node, nodePosition) + + removed = graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', newGraphId, node) + + # Verify that the created Entity for this node matches the Entity that gets + # deleted when the node is removed + Report.info(f"Node: {nodeName}") + Report.result(Tests.entity_deleted, removed and createdEntityId.invoke("Equal", deletedEntityId)) + + # Stop listening for entity creation/deletion notifications + handler.disconnect() -test = TestShapeNodeEntityDelete() -test.run() +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(ShapeNodes_EntityRemovedOnNodeDelete) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py new file mode 100644 index 0000000000..c5ab08f99a --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py @@ -0,0 +1,84 @@ +""" +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: + slice_created = ( + "Slice created successfully", + "Failed to create slice" + ) + slice_instantiated = ( + "Slice instantiated successfully", + "Failed to instantiate slice" + ) + + +def Slice_CreateInstantiate(): + """ + Summary: + A slice containing the LandscapeCanvas component can be created/instantiated. + + Expected Result: + Slice is created/processed/instantiated successfully and free of errors/warnings. + + Test Steps: + 1) Open a simple level + 2) Create a new entity with a Landscape Canvas component + 3) Create a slice of the new entity + 4) Instantiate a new copy of the slice + + 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 azlmbr.math as math + import azlmbr.bus as bus + import azlmbr.asset as asset + import azlmbr.slice as slice + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + + def path_is_valid_asset(asset_path): + asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False) + return asset_id.invoke("IsValid") + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Create entity with Landscape Canvas component + position = math.Vector3(512.0, 512.0, 32.0) + landscape_canvas = hydra.Entity("landscape_canvas_entity") + landscape_canvas.create_entity(position, ["Landscape Canvas"]) + + # Create slice from the created entity + slice_path = os.path.join("slices", "TestSlice.slice") + slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", landscape_canvas.id, slice_path) + + # Verify if slice is created + helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0) + Report.result(Tests.slice_created, path_is_valid_asset(slice_path)) + + # Instantiate slice + transform = math.Transform_CreateIdentity() + asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False) + test_slice = slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform) + helper.wait_for_condition(lambda: test_slice.IsValid(), 5.0) + Report.result(Tests.slice_instantiated, test_slice.IsValid()) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Slice_CreateInstantiate) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py index 2156795b1a..3169908621 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py @@ -5,210 +5,217 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os -import sys -import azlmbr.bus as bus -import azlmbr.editor as editor -import azlmbr.editor.graph as graph -import azlmbr.landscapecanvas as landscapecanvas -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths +class Tests: + lc_tool_opened = ( + "Landscape Canvas tool opened", + "Failed to open Landscape Canvas tool" + ) + new_graph_created = ( + "Successfully created new graph", + "Failed to create new graph" + ) + graph_registered = ( + "Graph registered with Landscape Canvas", + "Failed to register graph" + ) + preview_entity_set = ( + "Random Noise Gradient component Preview Entity property set to Box Shape EntityId", + "Unexpected entity set in Random Noise Gradient Preview Entity property" + ) + dither_inbound_gradient_set = ( + "Dither Gradient Modifier component Inbound Gradient property set to Random Noise Gradient EntityId", + "Unexpected entity set in Dither Gradient's Inbound Gradient property" + ) + mixer_inbound_gradient_set = ( + "Gradient Mixer component Inbound Gradient extendable property set to Dither Gradient Modifier EntityId", + "Unexpected entity set in Gradient Mixer's Inbound Gradient property" + ) -sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.editor_test_helper import EditorTestHelper -editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID newEntityId = None -class TestSlotConnectionsUpdateComponents(EditorTestHelper): - def __init__(self): - EditorTestHelper.__init__(self, log_prefix="SlotConnectionsUpdateComponents", args=["level"]) +def SlotConnections_UpdateComponentReferences(): + """ + Summary: + This test verifies that the Landscape Canvas slot connections properly update component references. - def run_test(self): - """ - Summary: - This test verifies that the Landscape Canvas slot connections properly update component references. + Expected Behavior: + A reference created through slot connections in Landscape Canvas is reflected in the Entity Inspector. - Expected Behavior: - A reference created through slot connections in Landscape Canvas is reflected in the Entity Inspector. + Test Steps: + 1) Open an existing level + 2) Open Landscape Canvas and create a new graph + 3) Several nodes are added to a graph, and connections are set between the nodes + 4) Component references are verified via Entity Inspector - Test Steps: - 1) Create a new level - 2) Open Landscape Canvas and create a new graph - 3) Several nodes are added to a graph, and connections are set between the nodes - 4) Component references are verified via Entity Inspector + 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. - 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 azlmbr.bus as bus + import azlmbr.editor as editor + import azlmbr.editor.graph as graph + import azlmbr.landscapecanvas as landscapecanvas + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths - :return: None - """ + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper - # Retrieve the proper component TypeIds per component name - componentNames = [ - 'Random Noise Gradient', - 'Dither Gradient Modifier', - 'Gradient Mixer' - ] - componentTypeIds = hydra.get_component_type_id_map(componentNames) - - # Helper method for retrieving an EntityId from a specific property on a component - def getEntityIdFromComponentProperty(targetEntityId, componentTypeName, propertyPath): - componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', targetEntityId, - componentTypeIds[componentTypeName]) - if not componentOutcome.IsSuccess(): - return None - - component = componentOutcome.GetValue() - propertyOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, - propertyPath) - if not propertyOutcome.IsSuccess(): - return None - - return propertyOutcome.GetValue() - - def onEntityCreated(parameters): - global newEntityId - newEntityId = parameters[0] - - # Create a new empty level - self.test_success = self.create_level( - self.args["level"], - heightmap_resolution=128, - heightmap_meters_per_pixel=1, - terrain_texture_resolution=128, - use_terrain=False, - ) - - # Open Landscape Canvas tool and verify - general.open_pane('Landscape Canvas') - self.test_success = self.test_success and general.is_pane_visible('Landscape Canvas') - if general.is_pane_visible('Landscape Canvas'): - self.log('Landscape Canvas pane is open') - - # Create a new graph in Landscape Canvas - newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) - self.test_success = self.test_success and newGraphId - if newGraphId: - self.log("New graph created") - - # Make sure the graph we created is in Landscape Canvas - success = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) - self.test_success = self.test_success and success - if success: - self.log("Graph registered with Landscape Canvas") - - # Listen for entity creation notifications so we can verify the component EntityId - # references are set correctly when connecting slots on the nodes - handler = editor.EditorEntityContextNotificationBusHandler() - handler.connect() - handler.add_callback('OnEditorEntityCreated', onEntityCreated) - - positionX = 10.0 - positionY = 10.0 - offsetX = 340.0 - offsetY = 100.0 - - # Add a box shape node to the graph - newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) - boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'BoxShapeNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, - positionY)) - boxShapeEntityId = newEntityId - - positionX += offsetX - positionY += offsetY - - # Add a random noise gradient node to the graph - randomNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'RandomNoiseGradientNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, randomNoiseNode, math.Vector2(positionX, - positionY)) - randomNoiseEntityId = newEntityId - - positionX += offsetX - positionY += offsetY - - # Add a dither gradient modifier node to the graph - ditherNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'DitherGradientModifierNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, ditherNode, math.Vector2(positionX, - positionY)) - ditherEntityId = newEntityId - - positionX += offsetX - positionY += offsetY - - # Add a gradient mixer node to the graph - gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', - newGraph, 'GradientMixerNode') - graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, - positionY)) - gradientMixerEntityId = newEntityId - - boundsSlotId = graph.GraphModelSlotId('Bounds') - previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') - inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') - outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') - - # Connect slots on our nodes to test all slot types like so: - # Shape -> Gradient -> Gradient Modifier -> Gradient Mixer - # - # Which tests the following slot types: - # * Shape -> Preview Bounds - # * Gradient Output -> Gradient Modifier - # * Gradient Output -> Gradient Mixer (extendable slots) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, - randomNoiseNode, previewBoundsSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, randomNoiseNode, - outboundGradientSlotId, ditherNode, inboundGradientSlotId) - graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, ditherNode, - outboundGradientSlotId, gradientMixerNode, inboundGradientSlotId) - - # Delay to allow all the underlying component properties to be updated after the slot connections are made - general.idle_wait(1.0) - - # Verify the Preview EntityId property on our Random Noise Gradient component has been set to our Box Shape's - # EntityId - previewEntityId = getEntityIdFromComponentProperty(randomNoiseEntityId, 'Random Noise Gradient', - 'Preview Settings|Pin Preview to Shape') - random_gradient_success = previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId) - self.test_success = self.test_success and random_gradient_success - if random_gradient_success: - self.log("Random Noise Gradient component Preview Entity property set to Box Shape EntityId") - - # Verify the Inbound Gradient EntityId property on our Dither Gradient Modifier component has been set to our - # Random Noise Gradient's EntityId - inboundGradientEntityId = getEntityIdFromComponentProperty(ditherEntityId, 'Dither Gradient Modifier', - 'Configuration|Gradient|Gradient Entity Id') - dither_gradient_success = inboundGradientEntityId and randomNoiseEntityId.invoke("Equal", - inboundGradientEntityId) - self.test_success = self.test_success and dither_gradient_success - if dither_gradient_success: - self.log("Dither Gradient Modifier component Inbound Gradient property set to Random Noise Gradient " - "EntityId") - - # Verify the Inbound Gradient Mixer EntityId property on our Gradient Mixer component has been set to our - # Dither Gradient Modifier's EntityId - inboundGradientMixerEntityId = getEntityIdFromComponentProperty(gradientMixerEntityId, 'Gradient Mixer', - 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') - gradient_mixer_success = inboundGradientMixerEntityId and ditherEntityId.invoke("Equal", - inboundGradientMixerEntityId) - self.test_success = self.test_success and gradient_mixer_success - if gradient_mixer_success: - self.log("Gradient Mixer component Inbound Gradient extendable property set to Dither Gradient Modifier " - "EntityId") - - # Stop listening for entity creation notifications - handler.disconnect() + editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID -test = TestSlotConnectionsUpdateComponents() -test.run() + # Retrieve the proper component TypeIds per component name + componentNames = [ + 'Random Noise Gradient', + 'Dither Gradient Modifier', + 'Gradient Mixer' + ] + componentTypeIds = hydra.get_component_type_id_map(componentNames) + + # Helper method for retrieving an EntityId from a specific property on a component + def getEntityIdFromComponentProperty(targetEntityId, componentTypeName, propertyPath): + componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', targetEntityId, + componentTypeIds[componentTypeName]) + + if not componentOutcome.IsSuccess(): + return None + + component = componentOutcome.GetValue() + propertyOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, + propertyPath) + if not propertyOutcome.IsSuccess(): + return None + + return propertyOutcome.GetValue() + + def onEntityCreated(parameters): + global newEntityId + newEntityId = parameters[0] + + # Open an existing simple level + helper.init_idle() + helper.open_level("Physics", "Base") + + # Open Landscape Canvas tool and verify + general.open_pane('Landscape Canvas') + Report.critical_result(Tests.lc_tool_opened, general.is_pane_visible('Landscape Canvas')) + + # Create a new graph in Landscape Canvas + newGraphId = graph.AssetEditorRequestBus(bus.Event, 'CreateNewGraph', editorId) + Report.critical_result(Tests.new_graph_created, newGraphId is not None) + + # Make sure the graph we created is in Landscape Canvas + graph_registered = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) + Report.result(Tests.graph_registered, graph_registered) + + # Listen for entity creation notifications so we can verify the component EntityId + # references are set correctly when connecting slots on the nodes + handler = editor.EditorEntityContextNotificationBusHandler() + handler.connect() + handler.add_callback('OnEditorEntityCreated', onEntityCreated) + + positionX = 10.0 + positionY = 10.0 + offsetX = 340.0 + offsetY = 100.0 + + # Add a box shape node to the graph + newGraph = graph.GraphManagerRequestBus(bus.Broadcast, 'GetGraph', newGraphId) + boxShapeNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'BoxShapeNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, boxShapeNode, math.Vector2(positionX, + positionY)) + boxShapeEntityId = newEntityId + + positionX += offsetX + positionY += offsetY + + # Add a random noise gradient node to the graph + randomNoiseNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'RandomNoiseGradientNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, randomNoiseNode, math.Vector2(positionX, + positionY)) + randomNoiseEntityId = newEntityId + + positionX += offsetX + positionY += offsetY + + # Add a dither gradient modifier node to the graph + ditherNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'DitherGradientModifierNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, ditherNode, math.Vector2(positionX, + positionY)) + ditherEntityId = newEntityId + + positionX += offsetX + positionY += offsetY + + # Add a gradient mixer node to the graph + gradientMixerNode = landscapecanvas.LandscapeCanvasNodeFactoryRequestBus(bus.Broadcast, 'CreateNodeForTypeName', + newGraph, 'GradientMixerNode') + graph.GraphControllerRequestBus(bus.Event, 'AddNode', newGraphId, gradientMixerNode, math.Vector2(positionX, + positionY)) + gradientMixerEntityId = newEntityId + + boundsSlotId = graph.GraphModelSlotId('Bounds') + previewBoundsSlotId = graph.GraphModelSlotId('PreviewBounds') + inboundGradientSlotId = graph.GraphModelSlotId('InboundGradient') + outboundGradientSlotId = graph.GraphModelSlotId('OutboundGradient') + + # Connect slots on our nodes to test all slot types like so: + # Shape -> Gradient -> Gradient Modifier -> Gradient Mixer + # + # Which tests the following slot types: + # * Shape -> Preview Bounds + # * Gradient Output -> Gradient Modifier + # * Gradient Output -> Gradient Mixer (extendable slots) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, boxShapeNode, boundsSlotId, + randomNoiseNode, previewBoundsSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, randomNoiseNode, + outboundGradientSlotId, ditherNode, inboundGradientSlotId) + graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', newGraphId, ditherNode, + outboundGradientSlotId, gradientMixerNode, inboundGradientSlotId) + + # Delay to allow all the underlying component properties to be updated after the slot connections are made + general.idle_wait(1.0) + + + # Verify the Preview EntityId property on our Random Noise Gradient component has been set to our Box Shape's + # EntityId + previewEntityId = getEntityIdFromComponentProperty(randomNoiseEntityId, 'Random Noise Gradient', + 'Preview Settings|Pin Preview to Shape') + random_gradient_success = previewEntityId and boxShapeEntityId.invoke("Equal", previewEntityId) + Report.result(Tests.preview_entity_set, random_gradient_success) + + # Verify the Inbound Gradient EntityId property on our Dither Gradient Modifier component has been set to our + # Random Noise Gradient's EntityId + inboundGradientEntityId = getEntityIdFromComponentProperty(ditherEntityId, 'Dither Gradient Modifier', + 'Configuration|Gradient|Gradient Entity Id') + dither_gradient_success = inboundGradientEntityId and randomNoiseEntityId.invoke("Equal", + inboundGradientEntityId) + Report.result(Tests.dither_inbound_gradient_set, dither_gradient_success) + + # Verify the Inbound Gradient Mixer EntityId property on our Gradient Mixer component has been set to our + # Dither Gradient Modifier's EntityId + inboundGradientMixerEntityId = getEntityIdFromComponentProperty(gradientMixerEntityId, 'Gradient Mixer', + 'Configuration|Layers|[0]|Gradient|Gradient Entity Id') + gradient_mixer_success = inboundGradientMixerEntityId and ditherEntityId.invoke("Equal", + inboundGradientMixerEntityId) + Report.result(Tests.mixer_inbound_gradient_set, gradient_mixer_success) + + # Stop listening for entity creation notifications + handler.disconnect() + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(SlotConnections_UpdateComponentReferences) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py new file mode 100644 index 0000000000..af4855a546 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main.py @@ -0,0 +1,29 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest +import sys + +import ly_test_tools.environment.file_system as file_system + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') +from base import TestAutomationBase + + +@pytest.mark.SUITE_main +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(self, request, workspace, editor, launcher_platform): + from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientMixer_NodeConstruction(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientMixer_NodeConstruction as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py new file mode 100644 index 0000000000..68bac24452 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Main_Optimized.py @@ -0,0 +1,22 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import pytest + +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + + class test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(EditorSharedTest): + from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module + + class test_LandscapeCanvas_GradientMixer_NodeConstruction(EditorSharedTest): + from .EditorScripts import GradientMixer_NodeConstruction as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py new file mode 100644 index 0000000000..ef8b3e492b --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic.py @@ -0,0 +1,121 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest +import sys + +import ly_test_tools.environment.file_system as file_system + +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') +from base import TestAutomationBase + + +@pytest.fixture +def remove_test_slice(request, workspace, project): + file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice.slice")], True, True) + + def teardown(): + file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice.slice")], True, + True) + + request.addfinalizer(teardown) + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(TestAutomationBase): + + def test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(self, request, workspace, editor, launcher_platform): + from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(self, request, workspace, editor, launcher_platform): + from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Edit_DisabledNodeDuplication(self, request, workspace, editor, launcher_platform): + from .EditorScripts import Edit_DisabledNodeDuplication as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Edit_UndoNodeDelete_SliceEntity(self, request, workspace, editor, launcher_platform): + from .EditorScripts import Edit_UndoNodeDelete_SliceEntity as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_NewGraph_CreatedSuccessfully(self, request, workspace, editor, launcher_platform): + from .EditorScripts import NewGraph_CreatedSuccessfully as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Component_AddedRemoved(self, request, workspace, editor, launcher_platform): + from .EditorScripts import Component_AddedRemoved as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GraphClosed_OnLevelChange(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphClosed_OnLevelChange as test_module + self._run_test(request, workspace, editor, test_module) + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") + def test_LandscapeCanvas_GraphClosed_OnEntityDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphClosed_OnEntityDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphClosed_TabbedGraph as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_Slice_CreateInstantiate(self, request, workspace, editor, remove_test_slice, launcher_platform): + from .EditorScripts import Slice_CreateInstantiate as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_GraphUpdates_UpdateComponents(self, request, workspace, editor, launcher_platform): + from .EditorScripts import GraphUpdates_UpdateComponents as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_ComponentUpdates_UpdateGraph(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ComponentUpdates_UpdateGraph as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_LayerBlender_NodeConstruction(self, request, workspace, editor, launcher_platform): + from .EditorScripts import LayerBlender_NodeConstruction as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module + self._run_test(request, workspace, editor, test_module) + + def test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): + from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module + self._run_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py new file mode 100644 index 0000000000..59e8b1fe90 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/test_LandscapeCanvas_Periodic_Optimized.py @@ -0,0 +1,89 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import os +import pytest + +import ly_test_tools.environment.file_system as file_system +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite + + +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomation(EditorTestSuite): + + class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module + + class test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(EditorSharedTest): + from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module + + class test_LandscapeCanvas_Edit_DisabledNodeDuplication(EditorSharedTest): + from .EditorScripts import Edit_DisabledNodeDuplication as test_module + + class test_LandscapeCanvas_Edit_UndoNodeDelete_SliceEntity(EditorSharedTest): + from .EditorScripts import Edit_UndoNodeDelete_SliceEntity as test_module + + class test_LandscapeCanvas_NewGraph_CreatedSuccessfully(EditorSharedTest): + from .EditorScripts import NewGraph_CreatedSuccessfully as test_module + + class test_LandscapeCanvas_Component_AddedRemoved(EditorSharedTest): + from .EditorScripts import Component_AddedRemoved as test_module + + class test_LandscapeCanvas_GraphClosed_OnLevelChange(EditorSharedTest): + from .EditorScripts import GraphClosed_OnLevelChange as test_module + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") + class test_LandscapeCanvas_GraphClosed_OnEntityDelete(EditorSharedTest): + from .EditorScripts import GraphClosed_OnEntityDelete as test_module + + class test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(EditorSharedTest): + from .EditorScripts import GraphClosed_TabbedGraph as test_module + + class test_LandscapeCanvas_Slice_CreateInstantiate(EditorSingleTest): + # Custom teardown to remove slice asset created during test + def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): + file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices", + "TestSlice.slice")], True, True) + from .EditorScripts import Slice_CreateInstantiate as test_module + + class test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module + + class test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_GraphUpdates_UpdateComponents(EditorSharedTest): + from .EditorScripts import GraphUpdates_UpdateComponents as test_module + + class test_LandscapeCanvas_ComponentUpdates_UpdateGraph(EditorSharedTest): + from .EditorScripts import ComponentUpdates_UpdateGraph as test_module + + class test_LandscapeCanvas_LayerBlender_NodeConstruction(EditorSharedTest): + from .EditorScripts import LayerBlender_NodeConstruction as test_module + + class test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp index cb97632e07..b164323238 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp @@ -675,14 +675,14 @@ void AzAssetBrowserRequestHandler::OpenAssetInAssociatedEditor(const AZ::Data::A firstValidOpener = &openerDetails; } // bind a callback such that when the menu item is clicked, it sets that as the opener to use. - menu.addAction(openerDetails.m_iconToUse, QObject::tr(openerDetails.m_displayText.c_str()), mainWindow, AZStd::bind(switchToOpener, &openerDetails)); + menu.addAction(openerDetails.m_iconToUse, QObject::tr(openerDetails.m_displayText.c_str()), mainWindow, [switchToOpener, details = &openerDetails] { return switchToOpener(details); }); } } if (numValidOpeners > 1) // more than one option was added { menu.addSeparator(); - menu.addAction(QObject::tr("Cancel"), AZStd::bind(switchToOpener, nullptr)); // just something to click on to avoid doing anything. + menu.addAction(QObject::tr("Cancel"), [switchToOpener] { return switchToOpener(nullptr); }); // just something to click on to avoid doing anything. menu.exec(QCursor::pos()); } else if (numValidOpeners == 1) diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp index 92c33aefc2..b9f7e12e95 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.cpp @@ -145,7 +145,7 @@ bool UserPopupWidgetHandler::ReadValuesIntoGUI(size_t index, UserPropertyEditor* QWidget* FloatCurveHandler::CreateGUI(QWidget *pParent) { CSplineCtrl *cSpline = new CSplineCtrl(pParent); - cSpline->SetUpdateCallback(AZStd::bind(&FloatCurveHandler::OnSplineChange, this, AZStd::placeholders::_1)); + cSpline->SetUpdateCallback([this](CSplineCtrl* spl) { OnSplineChange(spl); }); cSpline->SetTimeRange(0, 1); cSpline->SetValueRange(0, 1); cSpline->SetGrid(12, 12); diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp index 303f86d270..af418c6e0d 100644 --- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp +++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyItem.cpp @@ -172,8 +172,8 @@ ReflectedPropertyItem::ReflectedPropertyItem(ReflectedPropertyControl *control, if (parent) parent->AddChild(this); - m_onSetCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableChange, this, AZStd::placeholders::_1); - m_onSetEnumCallback = AZStd::bind(&ReflectedPropertyItem::OnVariableEnumChange, this, AZStd::placeholders::_1); + m_onSetCallback = [this](IVariable* var) { OnVariableChange(var); }; + m_onSetEnumCallback = [this](IVariable* var) { OnVariableEnumChange(var); }; } ReflectedPropertyItem::~ReflectedPropertyItem() diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index c994458baa..6fcf3faffd 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -37,7 +37,7 @@ namespace UnitTest m_inputChannelMapper = AZStd::make_unique(m_rootWidget.get(), TestViewportId); } - void TearDown() + void TearDown() override { m_inputChannelMapper.reset(); diff --git a/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp b/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp index 9dc7e65cef..8c7023634e 100644 --- a/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp +++ b/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp @@ -24,10 +24,10 @@ namespace UnitTest void Disconnect(); // EditorInteractionSystemViewportSelectionRequestBus overrides ... - void SetHandler(const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder); - void SetDefaultHandler(); - bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction); - bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction); + void SetHandler(const AzToolsFramework::ViewportSelectionRequestsBuilderFn& interactionRequestsBuilder) override; + void SetDefaultHandler() override; + bool InternalHandleMouseViewportInteraction(const MouseInteractionEvent& mouseInteraction) override; + bool InternalHandleMouseManipulatorInteraction(const MouseInteractionEvent& mouseInteraction) override; AZStd::function m_internalHandleMouseViewportInteraction; AZStd::function m_internalHandleMouseManipulatorInteraction; @@ -92,7 +92,7 @@ namespace UnitTest m_inputChannelMapper = AZStd::make_unique(m_rootWidget.get(), TestViewportId); } - void TearDown() + void TearDown() override { m_inputChannelMapper.reset(); diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index fbd8e85482..fa2e792cc8 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -1767,7 +1767,7 @@ void MainWindow::RegisterOpenWndCommands() cmdUI.tooltip = (QString("Open ") + className).toUtf8().data(); cmdUI.iconFilename = className.toUtf8().data(); GetIEditor()->GetCommandManager()->RegisterUICommand("editor", openCommandName.toUtf8().data(), - "", "", AZStd::bind(&CEditorOpenViewCommand::Execute, pCmd), cmdUI); + "", "", [pCmd] { pCmd->Execute(); }, cmdUI); GetIEditor()->GetCommandManager()->GetUIInfo("editor", openCommandName.toUtf8().data(), cmdUI); } } diff --git a/Code/Editor/Objects/BaseObject.cpp b/Code/Editor/Objects/BaseObject.cpp index 59a58e1ac1..c89bd50559 100644 --- a/Code/Editor/Objects/BaseObject.cpp +++ b/Code/Editor/Objects/BaseObject.cpp @@ -1515,8 +1515,8 @@ void CBaseObject::Serialize(CObjectArchive& ar) SetFrozen(bFrozen); SetHidden(bHidden); - ar.SetResolveCallback(this, parentId, AZStd::bind(&CBaseObject::ResolveParent, this, AZStd::placeholders::_1 )); - ar.SetResolveCallback(this, lookatId, AZStd::bind(&CBaseObject::SetLookAt, this, AZStd::placeholders::_1)); + ar.SetResolveCallback(this, parentId, [this](CBaseObject* parent) { ResolveParent(parent); }); + ar.SetResolveCallback(this, lookatId, [this](CBaseObject* target) { SetLookAt(target); }); InvalidateTM(0); SetModified(false); diff --git a/Code/Editor/Objects/EntityObject.cpp b/Code/Editor/Objects/EntityObject.cpp index 45aaa7919e..68264f9ea4 100644 --- a/Code/Editor/Objects/EntityObject.cpp +++ b/Code/Editor/Objects/EntityObject.cpp @@ -230,25 +230,25 @@ CEntityObject::CEntityObject() m_attachmentType = eAT_Pivot; // cache all the variable callbacks, must match order of enum defined in header - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaHeightChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaLightChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaLightSizeChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnAreaWidthChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxHeightChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxLengthChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxProjectionChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxSizeXChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxSizeYChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxSizeZChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnBoxWidthChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnColorChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnInnerRadiusChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnOuterRadiusChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnProjectInAllDirsChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnProjectorFOVChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnProjectorTextureChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnPropertyChange, this, AZStd::placeholders::_1)); - m_onSetCallbacksCache.push_back(AZStd::bind(&CEntityObject::OnRadiusChange, this, AZStd::placeholders::_1)); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaHeightChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaLightChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaLightSizeChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnAreaWidthChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxHeightChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxLengthChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxProjectionChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxSizeXChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxSizeYChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxSizeZChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnBoxWidthChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnColorChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnInnerRadiusChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnOuterRadiusChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnProjectInAllDirsChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnProjectorFOVChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnProjectorTextureChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnPropertyChange(var); }); + m_onSetCallbacksCache.emplace_back([this](IVariable* var) { OnRadiusChange(var); }); } CEntityObject::~CEntityObject() @@ -938,11 +938,14 @@ void CEntityObject::Serialize(CObjectArchive& ar) eventTarget->getAttr("TargetId", targetId); eventTarget->getAttr("Event", et.event); eventTarget->getAttr("SourceEvent", et.sourceEvent); - m_eventTargets.push_back(et); + m_eventTargets.emplace_back(AZStd::move(et)); if (targetId != GUID_NULL) { using namespace AZStd::placeholders; - ar.SetResolveCallback(this, targetId, AZStd::bind(&CEntityObject::ResolveEventTarget, this, _1, _2), i); + ar.SetResolveCallback( + this, targetId, + [this](CBaseObject* object, unsigned int index) { ResolveEventTarget(object, index); }, + i); } } } diff --git a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp index 6a5c5b6427..2fd46b0fc5 100644 --- a/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp +++ b/Code/Editor/TrackView/TrackViewKeyPropertiesDlg.cpp @@ -110,7 +110,7 @@ void CTrackViewKeyPropertiesDlg::PopulateVariables() m_wndProps->RemoveAllItems(); m_wndProps->AddVarBlock(m_pVarBlock); - m_wndProps->SetUpdateCallback(AZStd::bind(&CTrackViewKeyPropertiesDlg::OnVarChange, this, AZStd::placeholders::_1)); + m_wndProps->SetUpdateCallback([this](IVariable* var) { OnVarChange(var); }); //m_wndProps->m_props.ExpandAll(); diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h index 0c4eaf8383..1c81a15bda 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h @@ -1850,7 +1850,7 @@ namespace AZ * { * // do any conversion of caching of the "data" here and forward this to behavior (often the reason for this is that you can't pass everything to behavior * // plus behavior can't really handle all constructs pointer to pointer, rvalues, etc. as they don't make sense for most script environments - * int result = 0; // set the default value for your result if the behavior if there is no implmentation + * int result = 0; // set the default value for your result if the behavior if there is no implementation * // The AZ_EBUS_BEHAVIOR_BINDER defines FN_EventName for each index. You can also cache it yourself (but it's slower), static int cacheIndex = GetFunctionIndex("OnEvent1"); and use that . * CallResult(result, FN_OnEvent1, data); // forward to the binding (there can be none, this is why we need to always have properly set result, when there is one) * return result; // return the result like you will in any normal EBus even with result diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 2e7cd1d170..08e238434e 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -102,11 +102,25 @@ namespace AzFramework static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; ////////////////////////////////////////////////////////////////////////// - virtual void OnTerrainDataCreateBegin() {}; - virtual void OnTerrainDataCreateEnd() {}; + enum TerrainDataChangedMask : uint8_t + { + None = 0b00000000, + Settings = 0b00000001, + HeightData = 0b00000010, + ColorData = 0b00000100, + SurfaceData = 0b00001000 + }; - virtual void OnTerrainDataDestroyBegin() {}; - virtual void OnTerrainDataDestroyEnd() {}; + virtual void OnTerrainDataCreateBegin() {} + virtual void OnTerrainDataCreateEnd() {} + + virtual void OnTerrainDataDestroyBegin() {} + virtual void OnTerrainDataDestroyEnd() {} + + virtual void OnTerrainDataChanged( + [[maybe_unused]] const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask) + { + } }; using TerrainDataNotificationBus = AZ::EBus; diff --git a/Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h b/Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h deleted file mode 100644 index 618131159e..0000000000 --- a/Code/Legacy/CryCommon/HeightmapUpdateNotificationBus.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -namespace AZ -{ - /** - * the EBus is used to request information about potential vegetation surfaces - */ - class HeightmapUpdateNotification - : public AZ::EBusTraits - { - public: - //////////////////////////////////////////////////////////////////////// - // EBusTraits - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; - static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - //////////////////////////////////////////////////////////////////////// - - // Occurs when the terrain height map is modified. - virtual void HeightmapModified(const AZ::Aabb& bounds) = 0; - }; - - typedef AZ::EBus HeightmapUpdateNotificationBus; -} diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index b8f73d064f..ba11de0215 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -53,7 +53,6 @@ set(FILES HMDBus.h VRCommon.h StereoRendererBus.h - HeightmapUpdateNotificationBus.h INavigationSystem.h IMNM.h SFunctor.h diff --git a/Code/Legacy/CrySystem/XConsole.cpp b/Code/Legacy/CrySystem/XConsole.cpp index 2293352f7e..46eea1528c 100644 --- a/Code/Legacy/CrySystem/XConsole.cpp +++ b/Code/Legacy/CrySystem/XConsole.cpp @@ -3133,6 +3133,9 @@ char* CXConsole::GetCheatVarAt(uint32 nOffset) ////////////////////////////////////////////////////////////////////////// size_t CXConsole::GetSortedVars(AZStd::vector& pszArray, const char* szPrefix) { + // This method used to insert instead of push_back, so we need to clear first + pszArray.clear(); + size_t iPrefixLen = szPrefix ? strlen(szPrefix) : 0; // variables diff --git a/Gems/Atom/Bootstrap/Code/CMakeLists.txt b/Gems/Atom/Bootstrap/Code/CMakeLists.txt index af09f3a288..1787af04ed 100644 --- a/Gems/Atom/Bootstrap/Code/CMakeLists.txt +++ b/Gems/Atom/Bootstrap/Code/CMakeLists.txt @@ -6,6 +6,8 @@ # # +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) + ly_add_target( NAME Atom_Bootstrap.Headers HEADERONLY NAMESPACE Gem @@ -21,9 +23,12 @@ ly_add_target( NAMESPACE Gem FILES_CMAKE bootstrap_files.cmake + ${pal_dir}/bootstrap_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake + PLATFORM_INCLUDE_FILES INCLUDE_DIRECTORIES PRIVATE Source + ${pal_dir} PUBLIC Include BUILD_DEPENDENCIES diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index f9d6ac63f7..11758138e0 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -38,6 +38,10 @@ #include #include +#include +#include + +AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name"); namespace AZ { @@ -50,8 +54,7 @@ namespace AZ if (SerializeContext* serialize = azrtti_cast(context)) { serialize->Class() - ->Version(0) - ->Field("DefaultRenderPipelineAssetFile", &BootstrapSystemComponent::m_defaultPipelineAssetPath) + ->Version(1) ; if (EditContext* ec = serialize->GetEditContext()) @@ -60,8 +63,6 @@ namespace AZ ->ClassElement(Edit::ClassElements::EditorData, "") ->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b)) ->Attribute(Edit::Attributes::AutoExpand, true) - ->DataElement(Edit::UIHandlers::Default, &BootstrapSystemComponent::m_defaultPipelineAssetPath, "Default RenderPipeline Asset", - "The asset file path of default render pipeline for default window") ; } } @@ -314,13 +315,15 @@ namespace AZ // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene. // When running with no Asset Processor (for example in release), CompileAssetSync will return AssetStatus_Unknown. AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; - AzFramework::AssetSystemRequestBus::BroadcastResult( - status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, m_defaultPipelineAssetPath); - AZ_Assert(status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, "Could not compile the default render pipeline at '%s'", m_defaultPipelineAssetPath.c_str()); + const AZ::CVarFixedString pipelineName = static_cast(r_default_pipeline_name); + AzFramework::AssetSystemRequestBus::BroadcastResult(status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, pipelineName.data()); + + AZ_Assert(status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, "Could not compile the default render pipeline at '%s'", pipelineName.c_str()); - Data::Asset pipelineAsset = RPI::AssetUtils::LoadAssetByProductPath(m_defaultPipelineAssetPath.c_str(), RPI::AssetUtils::TraceLevel::Error); + Data::Asset pipelineAsset = RPI::AssetUtils::LoadAssetByProductPath(pipelineName.data(), RPI::AssetUtils::TraceLevel::Error); RPI::RenderPipelineDescriptor renderPipelineDescriptor = *RPI::GetDataFromAnyAsset(pipelineAsset); renderPipelineDescriptor.m_name = AZStd::string::format("%s_%i", renderPipelineDescriptor.m_name.c_str(), viewportContext->GetId()); + if (!scene->GetRenderPipeline(AZ::Name(renderPipelineDescriptor.m_name))) { RPI::RenderPipelinePtr renderPipeline = RPI::RenderPipeline::CreateRenderPipelineForWindow(renderPipelineDescriptor, *viewportContext->GetWindowContext().get()); diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h index 142b2d8769..bd5d417b8f 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h @@ -112,10 +112,7 @@ namespace AZ // The id of the render pipeline created by this component RPI::RenderPipelineId m_renderPipelineId; - - // Variables which are system component configuration - AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; - + // Save a reference to the image created by the BRDF pipeline so it doesn't get auto deleted if it's ref count goes to zero // For example, if we delete all the passes, we won't have to recreate the BRDF pipeline to recreate the BRDF texture Data::Instance m_brdfTexture; diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..da63106e29 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/LowEndRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Android/bootstrap_android_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..d467de5e53 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Linux/bootstrap_linux_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..d467de5e53 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Mac/bootstrap_mac_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..d467de5e53 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/MainRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/Windows/bootstrap_windows_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h new file mode 100644 index 0000000000..da63106e29 --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/BootstrapSystemComponent_Traits_Platform.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#define AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME "passes/LowEndRenderPipeline.azasset" diff --git a/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake new file mode 100644 index 0000000000..bae11b561e --- /dev/null +++ b/Gems/Atom/Bootstrap/Code/Source/Platform/iOS/bootstrap_ios_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + BootstrapSystemComponent_Traits_Platform.h +) + diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset b/Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset new file mode 100644 index 0000000000..fd0c9bd0ed --- /dev/null +++ b/Gems/Atom/Feature/Common/Assets/Passes/LowEndRenderPipeline.azasset @@ -0,0 +1,15 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "RenderPipelineDescriptor", + "ClassData": { + "Name": "LowEndPipeline", + "MainViewTag": "MainCamera", + "RootPassTemplate": "LowEndPipelineTemplate", + "RenderSettings": { + "MultisampleState": { + "samples": 1 + } + } + } +} diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp index 383c5e5a79..05107128ad 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.cpp @@ -204,6 +204,7 @@ namespace AZ { RHI::Ptr nullMtlImagePtr = m_device->GetNullDescriptorManager().GetNullImage(shaderInputImage.m_type).GetMemory(); mtlTextures[imageArrayLen] = nullMtlImagePtr->GetGpuAddress>(); + m_useNullDescriptorHeap = true; } imageArrayLen++; } @@ -282,12 +283,16 @@ namespace AZ { RHI::Ptr nullMtlBufferMemPtr = nullDescriptorManager.GetNullImageBuffer().GetMemory(); mtlTextures[bufferArrayLen] = nullMtlBufferMemPtr->GetGpuAddress>(); + m_useNullDescriptorHeap = true; } else { RHI::Ptr nullMtlBufferMemPtr = nullDescriptorManager.GetNullBuffer().GetMemory(); mtlBuffers[bufferArrayLen] = nullMtlBufferMemPtr->GetGpuAddress>(); mtlBufferOffsets[bufferArrayLen] = nullDescriptorManager.GetNullBuffer().GetOffset(); + m_resourceBindings[shaderInputBuffer.m_name].insert( + ResourceBindingData{nullMtlBufferMemPtr, .m_bufferAccess = shaderInputBuffer.m_access} + ); } } @@ -499,5 +504,26 @@ namespace AZ resourcesToMakeResidentMap[key].emplace(mtlResourceToBind); } } + + bool ArgumentBuffer::IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const + { + bool isUsedByVertexStage = false; + + //Iterate over all the SRG entries + for (const auto& it : srgResourcesVisInfo.m_resourcesStageMask) + { + //Only the ones not added to m_resourceBindings would require null heap + if( m_resourceBindings.find(it.first) == m_resourceBindings.end()) + { + isUsedByVertexStage |= RHI::CheckBitsAny(it.second, RHI::ShaderStageMask::Vertex); + } + } + return isUsedByVertexStage; + } + + bool ArgumentBuffer::IsNullDescHeapNeeded() const + { + return m_useNullDescriptorHeap; + } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h index cf229aeb75..a680516dc6 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ArgumentBuffer.h @@ -104,6 +104,8 @@ namespace AZ GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const; void ClearResourceTracking(); + bool IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const; + bool IsNullDescHeapNeeded() const; ////////////////////////////////////////////////////////////////////////// // RHI::DeviceObject @@ -153,6 +155,7 @@ namespace AZ MemoryView m_argumentBuffer; MemoryView m_constantBuffer; #endif + bool m_useNullDescriptorHeap = false; }; } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp index 2614addfe3..3c45e69d8b 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandList.cpp @@ -245,6 +245,8 @@ namespace AZ bool CommandList::SetArgumentBuffers(const PipelineState* pipelineState, RHI::PipelineStateType stateType) { + bool bindNullDescriptorHeap = false; + MTLRenderStages mtlRenderStagesForNullDescHeap = 0; ShaderResourceBindings& bindings = GetShaderResourceBindingsByPipelineType(stateType); const PipelineLayout& pipelineLayout = pipelineState->GetPipelineLayout(); @@ -280,7 +282,8 @@ namespace AZ uint32_t srgVisIndex = pipelineLayout.GetIndexBySlot(shaderResourceGroup->GetBindingSlot()); const RHI::ShaderStageMask& srgVisInfo = pipelineLayout.GetSrgVisibility(srgVisIndex); - + const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); + bool isSrgUpdatd = bindings.m_srgsByIndex[slot] != shaderResourceGroup; if(isSrgUpdatd) { @@ -291,6 +294,9 @@ namespace AZ if(srgVisInfo != RHI::ShaderStageMask::None) { + bool isNullDescHeapNeeded = compiledArgBuffer.IsNullDescHeapNeeded(); + bindNullDescriptorHeap |= isNullDescHeapNeeded; + //For graphics and compute shader stages, cache all the argument buffers, offsets and track the min/max indices if(m_commandEncoderType == CommandEncoderType::Render) { @@ -300,7 +306,9 @@ namespace AZ mtlVertexArgBuffers[slotIndex] = argBuffer; mtlVertexArgBufferOffsets[slotIndex] = argBufferOffset; bufferVertexRegisterIdMin = AZStd::min(slotIndex, bufferVertexRegisterIdMin); - bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax); + bufferVertexRegisterIdMax = AZStd::max(slotIndex, bufferVertexRegisterIdMax); + mtlRenderStagesForNullDescHeap = shaderResourceGroup->IsNullHeapNeededForVertexStage(srgResourcesVisInfo) ? + mtlRenderStagesForNullDescHeap | MTLRenderStageVertex : mtlRenderStagesForNullDescHeap; } if( numBitsSet > 1 || srgVisInfo == RHI::ShaderStageMask::Fragment) @@ -309,6 +317,7 @@ namespace AZ mtlFragmentOrComputeArgBufferOffsets[slotIndex] = argBufferOffset; bufferFragmentOrComputeRegisterIdMin = AZStd::min(slotIndex, bufferFragmentOrComputeRegisterIdMin); bufferFragmentOrComputeRegisterIdMax = AZStd::max(slotIndex, bufferFragmentOrComputeRegisterIdMax); + mtlRenderStagesForNullDescHeap = isNullDescHeapNeeded ? mtlRenderStagesForNullDescHeap | MTLRenderStageFragment : mtlRenderStagesForNullDescHeap; } } else if(m_commandEncoderType == CommandEncoderType::Compute) @@ -329,7 +338,7 @@ namespace AZ bindings.m_srgVisHashByIndex[slot] = srgResourcesVisHash; if(srgVisInfo != RHI::ShaderStageMask::None) { - const ShaderResourceGroupVisibility& srgResourcesVisInfo = pipelineLayout.GetSrgResourcesVisibility(srgVisIndex); + //For graphics and compute encoder make the resource resident (call UseResource) for the duration //of the work associated with the current scope and ensure that it's in a @@ -396,6 +405,10 @@ namespace AZ stages: key.first.second]; } + if(bindNullDescriptorHeap) + { + MakeHeapsResident(mtlRenderStagesForNullDescHeap); + } return true; } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp index b3dd209926..e386c25515 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.cpp @@ -64,6 +64,7 @@ namespace AZ { [m_encoder endEncoding]; m_encoder = nil; + m_isNullDescHeapBound = false; #if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING if (m_supportsInterDrawTimestamps) { @@ -73,18 +74,25 @@ namespace AZ } } - void CommandListBase::MakeHeapsResident() + void CommandListBase::MakeHeapsResident(MTLRenderStages renderStages) { + if(m_isNullDescHeapBound) + { + return; + } + switch(m_commandEncoderType) { case CommandEncoderType::Render: { - id renderEncoder = GetEncoder>(); - for (id residentHeap : *m_residentHeaps) + if(renderStages != 0) { - //MTLRenderStageVertex is not added to this as it was causing an immediate gpu crash on ios (first buffer commit) - [renderEncoder useHeap : residentHeap - stages : MTLRenderStageFragment]; + id renderEncoder = GetEncoder>(); + for (id residentHeap : *m_residentHeaps) + { + [renderEncoder useHeap : residentHeap + stages : renderStages]; + } } break; } @@ -102,6 +110,7 @@ namespace AZ AZ_Assert(false, "Encoder Type not supported"); } } + m_isNullDescHeapBound = true; } void CommandListBase::CreateEncoder(CommandEncoderType encoderType) @@ -119,16 +128,12 @@ namespace AZ m_commandEncoderType = CommandEncoderType::Render; m_encoder = [m_mtlCommandBuffer renderCommandEncoderWithDescriptor : m_renderPassDescriptor]; m_renderPassDescriptor = nil; - MakeHeapsResident(); - break; } case CommandEncoderType::Compute: { m_commandEncoderType = CommandEncoderType::Compute; m_encoder = [m_mtlCommandBuffer computeCommandEncoder]; - MakeHeapsResident(); - break; } case CommandEncoderType::Blit: diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h index b2c548c9c5..2f8905d61c 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/CommandListBase.h @@ -89,12 +89,14 @@ namespace AZ /// Cache multisample state. Used mainly to validate the MSAA image descriptor against the one passed into the pipelinestate RHI::MultisampleState m_renderPassMultiSampleState; + //! Go through all the heaps and call UseHeap on them to make them resident for the upcoming pass. + void MakeHeapsResident(MTLRenderStages renderStages); private: - //! Go through all the heaps and call UseHeap on them to make them resident for the upcoming pass. - void MakeHeapsResident(); + bool m_isEncoded = false; + bool m_isNullDescHeapBound = false; RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics; NSString* m_encoderScopeName = nullptr; id m_mtlCommandBuffer = nil; diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp index 5288ec8e5a..e86ba3c2c3 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/NullDescriptorManager.cpp @@ -126,10 +126,10 @@ namespace AZ Device& device = static_cast(GetDevice()); m_nullBuffer.m_name = "NULL_DESCRIPTOR_BUFFER"; - m_nullBuffer.m_bufferDescriptor.m_byteCount = 64; + m_nullBuffer.m_bufferDescriptor.m_byteCount = 1024; m_nullBuffer.m_bufferDescriptor.m_bindFlags = RHI::BufferBindFlags::ShaderWrite; m_nullBuffer.m_memoryView = device.CreateBufferCommitted(m_nullBuffer.m_bufferDescriptor); - + m_nullBuffer.m_memoryView.SetName( m_nullBuffer.m_name.c_str()); if(!m_nullBuffer.m_memoryView.IsValid()) { AZ_Assert(false, "Couldnt create a null buffer for ArgumentTable"); diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp index 9c4e13f713..1cba62b988 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.cpp @@ -36,5 +36,10 @@ namespace AZ { GetCompiledArgumentBuffer().CollectUntrackedResources(commandEncoder, srgResourcesVisInfo, resourcesToMakeResidentCompute, resourcesToMakeResidentGraphics); } + + bool ShaderResourceGroup::IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const + { + return GetCompiledArgumentBuffer().IsNullHeapNeededForVertexStage(srgResourcesVisInfo); + } } } diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h index 52ffabe106..cb69c0975e 100644 --- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h +++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroup.h @@ -47,7 +47,8 @@ namespace AZ const ShaderResourceGroupVisibility& srgResourcesVisInfo, ArgumentBuffer::ComputeResourcesToMakeResidentMap& resourcesToMakeResidentCompute, ArgumentBuffer::GraphicsResourcesToMakeResidentMap& resourcesToMakeResidentGraphics) const; - + bool IsNullHeapNeededForVertexStage(const ShaderResourceGroupVisibility& srgResourcesVisInfo) const; + private: ShaderResourceGroup() = default; diff --git a/Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis b/Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis new file mode 100644 index 0000000000..64ad28af72 --- /dev/null +++ b/Gems/Atom/RPI/Code/Source/Platform/Common/VisualStudio/Natvis/shaderoptiongroup.natvis @@ -0,0 +1,23 @@ + + + + + + shader option group + + m_id.m_key + + + + iOption++ + + + + + ((m_id.m_key.m_bits[(int) (m_layout.px->m_options[iOption].m_bitOffset / m_id.m_key.BitsPerWord)] >> (m_layout.px->m_options[iOption].m_bitOffset - ((int) (m_layout.px->m_options[iOption].m_bitOffset / 32) * 32))) & ((1u << (m_layout.px->m_options[iOption].m_bitCount)) - 1u)) + (m_layout.px->m_options[iOption].m_minValue.m_index) + + + + + + diff --git a/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake b/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake index 057fecfc90..c805aa9577 100644 --- a/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake +++ b/Gems/Atom/RPI/Code/Source/Platform/Windows/platform_windows_files.cmake @@ -9,4 +9,5 @@ set(FILES Atom_RPI_Traits_Platform.h Atom_RPI_Traits_Windows.h + ../Common/VisualStudio/Natvis/shaderoptiongroup.natvis ) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h index 6421c877b0..d55755a242 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Application/AtomToolsApplication.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -113,6 +114,8 @@ namespace AtomToolsFramework AzToolsFramework::TraceLogger m_traceLogger; + AZStd::unique_ptr m_styleManager; + //! Local user settings are used to store material browser tree expansion state AZ::UserSettingsProvider m_localUserSettings; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 4cc98a15aa..b8426f7528 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -61,14 +63,26 @@ namespace AtomToolsFramework : Application(argc, argv) , AzQtApplication(*argc, *argv) { + // Suppress spam from the Source Control system + m_traceLogger.AddWindowFilter(AzToolsFramework::SCC_WINDOW); + + installEventFilter(new AzQtComponents::GlobalEventFilter(this)); + + AZ::IO::FixedMaxPath engineRootPath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + + m_styleManager.reset(new AzQtComponents::StyleManager(this)); + m_styleManager->initialize(this, engineRootPath); + connect(&m_timer, &QTimer::timeout, this, [&]() { this->PumpSystemEventLoopUntilEmpty(); this->Tick(); }); - // Suppress spam from the Source Control system - m_traceLogger.AddWindowFilter(AzToolsFramework::SCC_WINDOW); } AtomToolsApplication ::~AtomToolsApplication() diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp index de29c27b71..05a044db0b 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/main.cpp @@ -6,46 +6,19 @@ * */ -#if !defined(Q_MOC_RUN) #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#endif - int main(int argc, char** argv) { AzQtComponents::AzQtApplication::InitializeDpiScaling(); MaterialEditor::MaterialEditorApplication app(&argc, &argv); - if (!app.LaunchLocalServer()) + if (app.LaunchLocalServer()) { - return 0; + app.Start(AZ::ComponentApplication::Descriptor{}); + app.exec(); + app.Stop(); } - app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); - - AZ::IO::FixedMaxPath engineRootPath; - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - - AzQtComponents::StyleManager styleManager(&app); - styleManager.initialize(&app, engineRootPath); - - app.Start(AZ::ComponentApplication::Descriptor{}); - app.exec(); - app.Stop(); return 0; } diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp index cf3f25cf6c..8291ce587e 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/main.cpp @@ -6,46 +6,19 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include +#include int main(int argc, char** argv) { AzQtComponents::AzQtApplication::InitializeDpiScaling(); ShaderManagementConsole::ShaderManagementConsoleApplication app(&argc, &argv); - if (!app.LaunchLocalServer()) + if (app.LaunchLocalServer()) { - return 0; + app.Start(AZ::ComponentApplication::Descriptor{}); + app.exec(); + app.Stop(); } - app.installEventFilter(new AzQtComponents::GlobalEventFilter(&app)); - - AZ::IO::FixedMaxPath engineRootPath; - if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) - { - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - - AzQtComponents::StyleManager styleManager(&app); - styleManager.initialize(&app, engineRootPath); - - app.Start(AZ::ComponentApplication::Descriptor{}); - app.exec(); - app.Stop(); return 0; } diff --git a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h index bdfc28c34c..d4855306be 100644 --- a/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h +++ b/Gems/AtomLyIntegration/ImguiAtom/Code/Source/DebugConsole.h @@ -122,7 +122,6 @@ namespace AZ int m_currentHistoryIndex = -1; //!< The current index into the input history when browsing. int m_maxEntriesToDisplay = DefaultMaxEntriesToDisplay; //!< The maximum entries to display. int m_maxInputHistorySize = DefaultMaxInputHistorySize; //!< The maximum input history size. - int m_logLevelToSet = 0; //!< The minimum log level to set (see AZ::LogLevel). bool m_isShowing = false; //!< Is the debug console currently being displayed? bool m_autoScroll = true; //!< Should we auto-scroll as new entries are added? bool m_forceScroll = false; //!< Do we need to force scroll after input entered? diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp index 738806a912..9a95f8bfa0 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/AudioSystemImpl_wwise.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -1779,8 +1780,8 @@ namespace Audio AK::MemoryMgr::CategoryStats categoryStats; AK::MemoryMgr::GetCategoryStats(memInfo.m_poolId, categoryStats); - memInfo.m_memoryUsed = categoryStats.uUsed; - memInfo.m_peakUsed = categoryStats.uPeakUsed; + memInfo.m_memoryUsed = static_cast(categoryStats.uUsed); + memInfo.m_peakUsed = static_cast(categoryStats.uPeakUsed); memInfo.m_numAllocs = categoryStats.uAllocs; memInfo.m_numFrees = categoryStats.uFrees; } @@ -1789,9 +1790,9 @@ namespace Audio AK::MemoryMgr::GetGlobalStats(globalStats); auto& memInfo = m_debugMemoryInfo.back(); - memInfo.m_memoryReserved = globalStats.uReserved; - memInfo.m_memoryUsed = globalStats.uUsed; - memInfo.m_peakUsed = globalStats.uMax; + memInfo.m_memoryReserved = static_cast(globalStats.uReserved); + memInfo.m_memoryUsed = static_cast(globalStats.uUsed); + memInfo.m_peakUsed = static_cast(globalStats.uMax); // return the memory infos... return m_debugMemoryInfo; diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h b/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h index feb1cd8c0f..35d656c337 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h +++ b/Gems/AudioSystem/Code/Source/Engine/AudioInternalInterfaces.h @@ -769,124 +769,6 @@ namespace Audio return (eStatus == eARS_SUCCESS || eStatus == eARS_FAILURE); } -#if !defined(AUDIO_RELEASE) - // Debug Logging Helper - AZStd::string ToString() - { - static const AZStd::unordered_map managerRequests - { - { eAMRT_INIT_AUDIO_IMPL, "INIT IMPL" }, - { eAMRT_RELEASE_AUDIO_IMPL, "RELEASE IMPL" }, - { eAMRT_RESERVE_AUDIO_OBJECT_ID, "RESERVE OBJECT ID" }, - { eAMRT_CREATE_SOURCE, "CREATE SOURCE" }, - { eAMRT_DESTROY_SOURCE, "DESTROY SOURCE" }, - { eAMRT_PARSE_CONTROLS_DATA, "PARSE CONTROLS" }, - { eAMRT_PARSE_PRELOADS_DATA, "PARSE PRELOADS" }, - { eAMRT_CLEAR_CONTROLS_DATA, "CLEAR CONTROLS" }, - { eAMRT_CLEAR_PRELOADS_DATA, "CLEAR PRELOADS" }, - { eAMRT_PRELOAD_SINGLE_REQUEST, "PRELOAD SINGLE" }, - { eAMRT_UNLOAD_SINGLE_REQUEST, "UNLOAD SINGLE" }, - { eAMRT_UNLOAD_AFCM_DATA_BY_SCOPE, "UNLOAD SCOPE" }, - { eAMRT_REFRESH_AUDIO_SYSTEM, "REFRESH AUDIO SYSTEM" }, - { eAMRT_LOSE_FOCUS, "LOSE FOCUS" }, - { eAMRT_GET_FOCUS, "GET FOCUS" }, - { eAMRT_MUTE_ALL, "MUTE" }, - { eAMRT_UNMUTE_ALL, "UNMUTE" }, - { eAMRT_STOP_ALL_SOUNDS, "STOP ALL" }, - { eAMRT_DRAW_DEBUG_INFO, "DRAW DEBUG" }, - { eAMRT_CHANGE_LANGUAGE, "CHANGE LANGUAGE" }, - { eAMRT_SET_AUDIO_PANNING_MODE, "SET PANNING MODE" }, - }; - static const AZStd::unordered_map callbackRequests - { - { eACMRT_REPORT_STARTED_EVENT, "STARTED EVENT" }, - { eACMRT_REPORT_FINISHED_EVENT, "FINISHED EVENT" }, - { eACMRT_REPORT_FINISHED_TRIGGER_INSTANCE, "FINISHED TRIGGER INSTANCE" }, - }; - static const AZStd::unordered_map listenerRequests - { - { eALRT_SET_POSITION, "SET POSITION" }, - }; - static const AZStd::unordered_map objectRequests - { - { eAORT_PREPARE_TRIGGER, "PREPARE TRIGGER" }, - { eAORT_UNPREPARE_TRIGGER, "UNPREPARE TRIGGER" }, - { eAORT_EXECUTE_TRIGGER, "EXECUTE TRIGGER" }, - { eAORT_STOP_TRIGGER, "STOP TRIGGER" }, - { eAORT_STOP_ALL_TRIGGERS, "STOP ALL" }, - { eAORT_SET_POSITION, "SET POSITION" }, - { eAORT_SET_RTPC_VALUE, "SET RTPC" }, - { eAORT_SET_SWITCH_STATE, "SET SWITCH" }, - { eAORT_SET_ENVIRONMENT_AMOUNT, "SET ENV AMOUNT" }, - { eAORT_RESET_ENVIRONMENTS, "RESET ENVS" }, - { eAORT_RESET_RTPCS, "RESET RTPCS" }, - { eAORT_RELEASE_OBJECT, "RELEASE OBJECT" }, - { eAORT_EXECUTE_SOURCE_TRIGGER, "EXECUTE SOURCE TRIGGER" }, - { eAORT_SET_MULTI_POSITIONS, "SET MULTI POSITIONS" }, - }; - - std::stringstream ss; - - ss << "AudioRequest("; - - if (pData->eRequestType == eART_AUDIO_MANAGER_REQUEST) - { - ss << "AUDIO MANAGER : "; - auto requestStr = managerRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - - if (pData->eRequestType == eART_AUDIO_CALLBACK_MANAGER_REQUEST) - { - ss << "AUDIO CALLBACK MGR : "; - auto requestStr = callbackRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - - if (pData->eRequestType == eART_AUDIO_LISTENER_REQUEST) - { - ss << "AUDIO LISTENER : "; - auto requestStr = listenerRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - if (pData->eRequestType == eART_AUDIO_OBJECT_REQUEST) - { - ss << "AUDIO OBJECT : "; - auto requestStr = objectRequests.at(static_cast(pData.get())->eType); - ss << requestStr.c_str(); - } - - ss << "): ["; - if (nFlags & eARF_PRIORITY_NORMAL) - { - ss << "PRIORITY NORMAL, "; - } - if (nFlags & eARF_PRIORITY_HIGH) - { - ss << "PRIORITY HIGH, "; - } - if (nFlags & eARF_EXECUTE_BLOCKING) - { - ss << "EXECUTE BLOCKING, "; - } - if (nFlags & eARF_SYNC_CALLBACK) - { - ss << "SYNC CALLBACK, "; - } - if (nFlags & eARF_SYNC_FINISHED_CALLBACK) - { - ss << "SYNC FINISHED CALLBACK, "; - } - if (nFlags & eARF_THREAD_SAFE_PUSH) - { - ss << "THREAD SAFE PUSH, "; - } - ss << "]"; - - return AZStd::string(ss.str().c_str()); - } -#endif // !AUDIO_RELEASE - TATLEnumFlagsType nFlags; TAudioObjectID nAudioObjectID; void* pOwner; diff --git a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp index 43ab47266a..af1dfedfaa 100644 --- a/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/AudioSystem.cpp @@ -616,7 +616,7 @@ namespace Audio void CAudioSystem::ProcessRequestThreadSafe(CAudioRequestInternal request) { // Audio Thread! - AZ_PROFILE_SCOPE(Audio, "Thread-Safe Request: %s", request.ToString().c_str()); + AZ_PROFILE_SCOPE(Audio, "Process Thread-Safe Request"); if (m_oATL.CanProcessRequests()) { @@ -641,7 +641,7 @@ namespace Audio { // Todo: This should handle request priority, use request priority as bus Address and process in priority order. - AZ_PROFILE_SCOPE(Audio, "Normal Request: %s", request.ToString().c_str()); + AZ_PROFILE_SCOPE(Audio, "Process Normal Request"); AZ_Assert(g_mainThreadId != AZStd::this_thread::get_id(), "AudioSystem::ProcessRequestByPriority - called from Main thread!"); @@ -672,7 +672,7 @@ namespace Audio { if (!(request.nInternalInfoFlags & eARIF_WAITING_FOR_REMOVAL)) { - AZ_PROFILE_SCOPE(Audio, "Blocking Request: %s", request.ToString().c_str()); + AZ_PROFILE_SCOPE(Audio, "Process Blocking Request"); if (request.eStatus == eARS_NONE) { diff --git a/Gems/GameState/Code/CMakeLists.txt b/Gems/GameState/Code/CMakeLists.txt index 7aa99446cb..debedd8500 100644 --- a/Gems/GameState/Code/CMakeLists.txt +++ b/Gems/GameState/Code/CMakeLists.txt @@ -17,8 +17,8 @@ ly_add_target( PUBLIC Include BUILD_DEPENDENCIES - PRIVATE - Legacy::CryCommon + PUBLIC + AZ::AzCore ) ly_add_target( @@ -33,7 +33,6 @@ ly_add_target( Include BUILD_DEPENDENCIES PRIVATE - Legacy::CryCommon Gem::GameState.Static ) @@ -58,7 +57,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) BUILD_DEPENDENCIES PRIVATE AZ::AzTest - Legacy::CryCommon Gem::GameState.Static ) ly_add_googletest( diff --git a/Gems/GameStateSamples/Code/CMakeLists.txt b/Gems/GameStateSamples/Code/CMakeLists.txt index 34132e67b1..5d1d180de0 100644 --- a/Gems/GameStateSamples/Code/CMakeLists.txt +++ b/Gems/GameStateSamples/Code/CMakeLists.txt @@ -21,6 +21,7 @@ ly_add_target( INTERFACE Gem::GameState Gem::LocalUser + Gem::LyShine.Static Gem::SaveData.Static Gem::MessagePopup.Static Legacy::CryCommon @@ -47,6 +48,7 @@ ly_add_target( Gem::LmbrCentral ) -# Clients and Servers use the above module. There is no editor or tools module required. -ly_create_alias(NAME GameStateSamples.Clients NAMESPACE Gem TARGETS GameStateSamples) -ly_create_alias(NAME GameStateSamples.Servers NAMESPACE Gem TARGETS GameStateSamples) +# Clients and Servers use the above module, and it contains assets so is needed by builders. +ly_create_alias(NAME GameStateSamples.Clients NAMESPACE Gem TARGETS Gem::GameStateSamples) +ly_create_alias(NAME GameStateSamples.Servers NAMESPACE Gem TARGETS Gem::GameStateSamples) +ly_create_alias(NAME GameStateSamples.Builders NAMESPACE Gem TARGETS Gem::UiBasics.Builders Gem::LyShineExamples.Builders) diff --git a/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp b/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp index 24a29c97ab..f175619bf4 100644 --- a/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp +++ b/Gems/GameStateSamples/Code/Source/GameStateSamplesModule.cpp @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -55,6 +56,7 @@ namespace GameStateSamples //! class GameStateSamplesModule : public CryHooksModule + , public AZ::TickBus::Handler , public GameOptionRequestBus::Handler { public: @@ -86,6 +88,22 @@ namespace GameStateSamples { CryHooksModule::OnCrySystemInitialized(system, systemInitParams); + AZ::TickBus::Handler::BusConnect(); + } + + void OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]AZ::ScriptTimePoint scriptTimePoint) override + { + // Ideally this would be called at startup (either above in OnCrySystemInitialized, or better during AZ system component + // initialisation), but because the initial game state depends on loading a UI canvas using LYShine we need to wait until + // the first tick, because LyShine in turn is not properly initialized until UiRenderer::OnBootstrapSceneReady has been + // called, which doesn't happen until a queued tick event that gets called right at the end of initialisation before we + // enter the main game loop. + CreateAndPushInitialGameState(); + AZ::TickBus::Handler::BusDisconnect(); + } + + void CreateAndPushInitialGameState() + { REGISTER_INT("sys_primaryUserSelectionEnabled", 2, VF_NULL, "Controls whether the game forces selection of a primary user at startup.\n" "0 : Skip selection of a primary user at startup on all platform.\n" diff --git a/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl b/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl index 2c49710ddd..6a9fceabbf 100644 --- a/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl +++ b/Gems/LmbrCentral/Code/include/LmbrCentral/Component/EditorWrappedComponentBase.inl @@ -212,8 +212,11 @@ namespace LmbrCentral template void EditorWrappedComponentBase::OnEntityVisibilityChanged(bool visibility) { - m_visible = visibility; - ConfigurationChanged(); + if (m_visible != visibility) + { + m_visible = visibility; + ConfigurationChanged(); + } } template diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h index 1c8894d6c2..8a5fec869c 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkEntity/INetworkEntityManager.h @@ -59,7 +59,8 @@ namespace Multiplayer ( const PrefabEntityId& prefabEntryId, NetEntityRole netEntityRole, - const AZ::Transform& transform + const AZ::Transform& transform, + AutoActivate autoActivate = AutoActivate::Activate ) = 0; //! Creates new entities of the given archetype @@ -89,6 +90,11 @@ namespace Multiplayer //! @return the total number of entities tracked by this INetworkEntityManager instance virtual uint32_t GetEntityCount() const = 0; + //! Returns the Net Entity ID for a given AZ Entity ID. + //! @param entityId the AZ Entity ID + //! @return the Net Entity ID + virtual NetEntityId GetNetEntityIdById(const AZ::EntityId& entityId) const = 0; + //! Adds the provided entity to the internal entity map identified by the provided netEntityId. //! @param netEntityId the identifier to use for the added entity //! @param entity the entity to add to the internal entity map diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 84fdc9ae54..8cde9613b7 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -130,9 +130,9 @@ void {{ PropertyName }}({{ ', '.join(paramDefines) }}); {# #} -{% macro DeclareRpcInvocations(Component, Section, HandleOn, ProctectedSection) %} +{% macro DeclareRpcInvocations(Component, Section, HandleOn, IsProtected) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, Section, HandleOn) %} -{% if Property.attrib['IsPublic']|booleanTrue == ProctectedSection %} +{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} {{ DeclareRpcInvocation(Property, HandleOn) -}} {% endif %} {% endcall %} @@ -386,8 +386,6 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ DeclareNetworkPropertyAccessors(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareArchetypePropertyGetters(Component)|indent(8) -}} - {{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}} - {{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Client', 'Authority', false)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Client', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Autonomous', 'Authority', false)|indent(8) -}} @@ -445,8 +443,8 @@ namespace {{ Component.attrib['Namespace'] }} static AZStd::unique_ptr AllocateComponentInput(); - {{ ComponentBaseName }}() = default; - ~{{ ComponentBaseName }}() override = default; + {{ ComponentBaseName }}(); + ~{{ ComponentBaseName }}() override; void Init() override; void Activate() override; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index b89d1a2b2e..1ddb5d9d65 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -318,7 +318,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par constexpr AzNetworking::ReliabilityType isReliable = Multiplayer::ReliabilityType::Unreliable; {% endif %} +{% if InvokeFrom == 'Server' or InvokeFrom =='Client' %} + const Multiplayer::NetComponentId netComponentId = GetNetComponentId(); +{% else %} const Multiplayer::NetComponentId netComponentId = GetParent().GetNetComponentId(); +{% endif %} Multiplayer::NetworkEntityRpcMessage rpcMessage(Multiplayer::RpcDeliveryType::{{ InvokeFrom }}To{{ HandleOn }}, GetNetEntityId(), netComponentId, rpcId, isReliable); {% if paramNames|count > 0 %} {{ UpperFirst(Component.attrib['Name']) }}Internal::{{ UpperFirst(Property.attrib['Name']) }}RpcStruct rpcStruct({{ ', '.join(paramNames) }}); @@ -345,9 +349,9 @@ void {{ ClassName }}::Signal{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.jo {# #} -{% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, ProctectedSection) %} +{% macro DefineRpcInvocations(Component, ClassName, InvokeFrom, HandleOn, IsProtected) %} {% call(Property) AutoComponentMacros.ParseRemoteProcedures(Component, InvokeFrom, HandleOn) %} -{% if Property.attrib['IsPublic']|booleanTrue == ProctectedSection %} +{% if Property.attrib['IsPublic']|booleanTrue != IsProtected %} {{ DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) -}} {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} {{ DefineRpcSignal(Component, ClassName, Property, InvokeFrom) -}} @@ -1490,6 +1494,10 @@ namespace {{ Component.attrib['Namespace'] }} {% endif %} } + {{ ComponentBaseName }}::{{ ComponentBaseName }}() = default; + + {{ ComponentBaseName }}::~{{ ComponentBaseName }}() = default; + void {{ ComponentBaseName }}::Init() { if (m_netBindComponent == nullptr) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 497d35db7e..b0a8350982 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -643,6 +643,7 @@ namespace Multiplayer { controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId()); } + controlledEntity.Activate(); if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so { @@ -763,6 +764,7 @@ namespace Multiplayer { controlledEntityNetBindComponent->SetAllowAutonomy(true); } + controlledEntity.Activate(); } AZLOG_INFO("Multiplayer operating in %s mode", GetEnumString(m_agentType)); @@ -969,7 +971,7 @@ namespace Multiplayer NetworkEntityHandle MultiplayerSystemComponent::SpawnDefaultPlayerPrefab() { PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast(sv_defaultPlayerSpawnAsset).c_str())); - INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity()); + INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity(), Multiplayer::AutoActivate::DoNotActivate); NetworkEntityHandle controlledEntity; if (entityList.size() > 0) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index cff05b9151..69d2726c65 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -73,6 +73,11 @@ namespace Multiplayer return m_networkEntityTracker.Get(netEntityId); } + NetEntityId NetworkEntityManager::GetNetEntityIdById(const AZ::EntityId& entityId) const + { + return m_networkEntityTracker.Get(entityId); + } + uint32_t NetworkEntityManager::GetEntityCount() const { return static_cast(m_networkEntityTracker.size()); @@ -304,7 +309,7 @@ namespace Multiplayer } INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate( - const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole) + const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole, AutoActivate autoActivate) { INetworkEntityManager::EntityList returnList; @@ -354,6 +359,11 @@ namespace Multiplayer const NetEntityId netEntityId = NextId(); netBindComponent->PreInit(clone, prefabEntityId, netEntityId, netEntityRole); + if (autoActivate == AutoActivate::DoNotActivate) + { + clone->SetRuntimeActiveByDefault(false); + } + AzFramework::GameEntityContextRequestBus::Broadcast( &AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone); @@ -373,10 +383,11 @@ namespace Multiplayer ( const PrefabEntityId& prefabEntryId, NetEntityRole netEntityRole, - const AZ::Transform& transform + const AZ::Transform& transform, + AutoActivate autoActivate ) { - return CreateEntitiesImmediate(prefabEntryId, NextId(), netEntityRole, AutoActivate::Activate, transform); + return CreateEntitiesImmediate(prefabEntryId, NextId(), netEntityRole, autoActivate, transform); } INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate @@ -409,7 +420,7 @@ namespace Multiplayer if (entityIndex == PrefabEntityId::AllIndices) { - return CreateEntitiesImmediate(*netSpawnable, netEntityRole); + return CreateEntitiesImmediate(*netSpawnable, netEntityRole, autoActivate); } const AzFramework::Spawnable::EntityList& entities = netSpawnable->GetEntities(); diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h index fdd0201b7a..9ccc576447 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.h @@ -41,13 +41,15 @@ namespace Multiplayer MultiplayerComponentRegistry* GetMultiplayerComponentRegistry() override; HostId GetHostId() const override; ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override; + NetEntityId GetNetEntityIdById(const AZ::EntityId& entityId) const override; - EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole); + EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole, AutoActivate autoActivate); EntityList CreateEntitiesImmediate ( const PrefabEntityId& prefabEntryId, NetEntityRole netEntityRole, - const AZ::Transform& transform + const AZ::Transform& transform, + AutoActivate autoActivate = AutoActivate::Activate ) override; EntityList CreateEntitiesImmediate ( diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp index a70dd74bf9..e31907461b 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.cpp @@ -18,6 +18,7 @@ namespace Multiplayer ++m_addChangeDirty; AZ_Assert(m_entityMap.end() == m_entityMap.find(netEntityId), "Attempting to add the same entity to the entity map multiple times"); m_entityMap[netEntityId] = entity; + m_netEntityIdMap[entity->GetId()] = netEntityId; } NetworkEntityHandle NetworkEntityTracker::Get(NetEntityId netEntityId) @@ -32,6 +33,16 @@ namespace Multiplayer return ConstNetworkEntityHandle(entity, netEntityId, this); } + NetEntityId NetworkEntityTracker::Get(const AZ::EntityId& entityId) const + { + auto found = m_netEntityIdMap.find(entityId); + if (found != m_netEntityIdMap.end()) + { + return found->second; + } + return Multiplayer::InvalidNetEntityId; + } + bool NetworkEntityTracker::Exists(NetEntityId netEntityId) const { return (m_entityMap.find(netEntityId) != m_entityMap.end()); @@ -50,12 +61,22 @@ namespace Multiplayer void NetworkEntityTracker::erase(NetEntityId netEntityId) { ++m_deleteChangeDirty; - m_entityMap.erase(netEntityId); + + auto found = m_entityMap.find(netEntityId); + if (found != m_entityMap.end()) + { + m_netEntityIdMap.erase(found->second->GetId()); + m_entityMap.erase(found); + } } NetworkEntityTracker::EntityMap::iterator NetworkEntityTracker::erase(EntityMap::iterator iter) { ++m_deleteChangeDirty; + if (iter != m_entityMap.end()) + { + m_netEntityIdMap.erase(iter->second->GetId()); + } return m_entityMap.erase(iter); } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h index 7ff2d1da24..09238acaee 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.h @@ -22,6 +22,7 @@ namespace Multiplayer public: using EntityMap = AZStd::unordered_map; + using NetEntityIdMap = AZStd::unordered_map; using iterator = EntityMap::iterator; using const_iterator = EntityMap::const_iterator; @@ -36,6 +37,8 @@ namespace Multiplayer NetworkEntityHandle Get(NetEntityId netEntityId); ConstNetworkEntityHandle Get(NetEntityId netEntityId) const; + NetEntityId Get(const AZ::EntityId& entityId) const; + //! Returns true if the netEntityId exists. bool Exists(NetEntityId netEntityId) const; @@ -74,6 +77,7 @@ namespace Multiplayer private: EntityMap m_entityMap; + NetEntityIdMap m_netEntityIdMap; uint32_t m_deleteChangeDirty = 0; uint32_t m_addChangeDirty = 0; }; diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl index c22fbb0da2..44098336be 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityTracker.inl @@ -48,6 +48,7 @@ namespace Multiplayer inline void NetworkEntityTracker::clear() { m_entityMap.clear(); + m_netEntityIdMap.clear(); } inline uint32_t NetworkEntityTracker::GetChangeDirty(const AZ::Entity* entity) const diff --git a/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h b/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h index c72f725a07..29b3fac8c7 100644 --- a/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h +++ b/Gems/SurfaceData/Code/Include/SurfaceData/Utility/SurfaceDataUtility.h @@ -14,7 +14,6 @@ #include #include #include -#include namespace AZ { diff --git a/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp b/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp index 6c96ee9d27..4eef54669a 100644 --- a/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp +++ b/Gems/SurfaceData/Code/Source/SurfaceDataModule.cpp @@ -20,7 +20,7 @@ namespace SurfaceData SurfaceDataSystemComponent::CreateDescriptor(), SurfaceDataColliderComponent::CreateDescriptor(), SurfaceDataShapeComponent::CreateDescriptor(), - TerrainSurfaceDataSystemComponent::CreateDescriptor(), + Terrain::TerrainSurfaceDataSystemComponent::CreateDescriptor(), }); } @@ -28,7 +28,7 @@ namespace SurfaceData { return AZ::ComponentTypeList{ azrtti_typeid(), - azrtti_typeid(), + azrtti_typeid(), }; } } diff --git a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp index 0f6eec73cd..a60bbc4034 100644 --- a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp +++ b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.cpp @@ -6,20 +6,16 @@ * */ -#include "TerrainSurfaceDataSystemComponent.h" +#include #include #include #include #include -#include -#include #include #include #include -#include - -namespace SurfaceData +namespace Terrain { ////////////////////////////////////////////////////////////////////////// // TerrainSurfaceDataSystemConfig @@ -98,26 +94,23 @@ namespace SurfaceData void TerrainSurfaceDataSystemComponent::Activate() { - m_providerHandle = InvalidSurfaceDataRegistryHandle; - m_system = GetISystem(); - CrySystemEventBus::Handler::BusConnect(); - AZ::HeightmapUpdateNotificationBus::Handler::BusConnect(); + m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; + AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); UpdateTerrainData(AZ::Aabb::CreateNull()); } void TerrainSurfaceDataSystemComponent::Deactivate() { - if (m_providerHandle != InvalidSurfaceDataRegistryHandle) + if (m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle) { - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); - m_providerHandle = InvalidSurfaceDataRegistryHandle; + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); + m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; } - SurfaceDataProviderRequestBus::Handler::BusDisconnect(); - AZ::HeightmapUpdateNotificationBus::Handler::BusDisconnect(); - CrySystemEventBus::Handler::BusDisconnect(); - m_system = nullptr; + SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect(); + AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect(); // Clear the cached terrain bounds data { @@ -146,17 +139,8 @@ namespace SurfaceData return false; } - void TerrainSurfaceDataSystemComponent::OnCrySystemInitialized(ISystem& system, [[maybe_unused]] const SSystemInitParams& systemInitParams) - { - m_system = &system; - } - - void TerrainSurfaceDataSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) - { - m_system = nullptr; - } - - void TerrainSurfaceDataSystemComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const + void TerrainSurfaceDataSystemComponent::GetSurfacePoints( + const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const { if (m_terrainBoundsIsValid) { @@ -168,12 +152,13 @@ namespace SurfaceData const float terrainHeight = terrain->GetHeight(inPosition, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, &isTerrainValidAtPoint); const bool isHole = !isTerrainValidAtPoint; - SurfacePoint point; + SurfaceData::SurfacePoint point; point.m_entityId = GetEntityId(); point.m_position = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), terrainHeight); point.m_normal = terrain->GetNormal(inPosition); - const AZ::Crc32 terrainTag = isHole ? Constants::s_terrainHoleTagCrc : Constants::s_terrainTagCrc; - AddMaxValueForMasks(point.m_masks, terrainTag, 1.0f); + const AZ::Crc32 terrainTag = + isHole ? SurfaceData::Constants::s_terrainHoleTagCrc : SurfaceData::Constants::s_terrainTagCrc; + SurfaceData::AddMaxValueForMasks(point.m_masks, terrainTag, 1.0f); surfacePointList.push_back(point); } // Only one handler should exist. @@ -189,11 +174,11 @@ namespace SurfaceData return terrain ? terrain->GetTerrainAabb() : AZ::Aabb::CreateNull(); } - SurfaceTagVector TerrainSurfaceDataSystemComponent::GetSurfaceTags() const + SurfaceData::SurfaceTagVector TerrainSurfaceDataSystemComponent::GetSurfaceTags() const { - SurfaceTagVector tags; - tags.push_back(Constants::s_terrainHoleTagCrc); - tags.push_back(Constants::s_terrainTagCrc); + SurfaceData::SurfaceTagVector tags; + tags.push_back(SurfaceData::Constants::s_terrainHoleTagCrc); + tags.push_back(SurfaceData::Constants::s_terrainTagCrc); return tags; } @@ -203,7 +188,7 @@ namespace SurfaceData bool terrainValidAfterUpdate = false; AZ::Aabb terrainBoundsBeforeUpdate = m_terrainBounds; - SurfaceDataRegistryEntry registryEntry; + SurfaceData::SurfaceDataRegistryEntry registryEntry; registryEntry.m_entityId = GetEntityId(); registryEntry.m_bounds = GetSurfaceAabb(); registryEntry.m_tags = GetSurfaceTags(); @@ -215,38 +200,44 @@ namespace SurfaceData if (terrainValidBeforeUpdate && terrainValidAfterUpdate) { - AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); + AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); // Our terrain was valid before and after, it just changed in some way. If we have a valid dirty region passed in // then it's possible that the heightmap has been modified in the Editor. Otherwise, just notify that the entire // terrain has changed in some way. if (dirtyRegion.IsValid()) { - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::RefreshSurfaceData, dirtyRegion); + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::RefreshSurfaceData, dirtyRegion); } else { - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UpdateSurfaceDataProvider, m_providerHandle, registryEntry); + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::UpdateSurfaceDataProvider, m_providerHandle, registryEntry); } } else if (!terrainValidBeforeUpdate && terrainValidAfterUpdate) { // Our terrain has become valid, so register as a provider and save off the registry handles - AZ_Assert((m_providerHandle == InvalidSurfaceDataRegistryHandle), "Surface Provider data handle is initialized before our terrain became valid"); - SurfaceDataSystemRequestBus::BroadcastResult(m_providerHandle, &SurfaceDataSystemRequestBus::Events::RegisterSurfaceDataProvider, registryEntry); + AZ_Assert( + (m_providerHandle == SurfaceData::InvalidSurfaceDataRegistryHandle), + "Surface Provider data handle is initialized before our terrain became valid"); + SurfaceData::SurfaceDataSystemRequestBus::BroadcastResult( + m_providerHandle, &SurfaceData::SurfaceDataSystemRequestBus::Events::RegisterSurfaceDataProvider, registryEntry); // Start listening for surface data events - AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); - SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle); + AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); + SurfaceData::SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle); } else if (terrainValidBeforeUpdate && !terrainValidAfterUpdate) { // Our terrain has stopped being valid, so unregister and stop listening for surface data events - AZ_Assert((m_providerHandle != InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); - SurfaceDataSystemRequestBus::Broadcast(&SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); - m_providerHandle = InvalidSurfaceDataRegistryHandle; + AZ_Assert((m_providerHandle != SurfaceData::InvalidSurfaceDataRegistryHandle), "Invalid surface data handle"); + SurfaceData::SurfaceDataSystemRequestBus::Broadcast( + &SurfaceData::SurfaceDataSystemRequestBus::Events::UnregisterSurfaceDataProvider, m_providerHandle); + m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; - SurfaceDataProviderRequestBus::Handler::BusDisconnect(); + SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect(); } else { @@ -255,8 +246,9 @@ namespace SurfaceData } - void TerrainSurfaceDataSystemComponent::HeightmapModified(const AZ::Aabb& bounds) + void TerrainSurfaceDataSystemComponent::OnTerrainDataChanged( + const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask) { - UpdateTerrainData(bounds); + UpdateTerrainData(dirtyRegion); } } diff --git a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h index aa5f4ab04c..a742eab78c 100644 --- a/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h +++ b/Gems/SurfaceData/Code/Source/TerrainSurfaceDataSystemComponent.h @@ -10,12 +10,11 @@ #include #include #include -#include -#include +#include #include #include -namespace SurfaceData +namespace Terrain { class TerrainSurfaceDataSystemConfig : public AZ::ComponentConfig @@ -31,9 +30,8 @@ namespace SurfaceData */ class TerrainSurfaceDataSystemComponent : public AZ::Component - , private SurfaceDataProviderRequestBus::Handler - , private AZ::HeightmapUpdateNotificationBus::Handler - , private CrySystemEventBus::Handler + , private SurfaceData::SurfaceDataProviderRequestBus::Handler + , private AzFramework::Terrain::TerrainDataNotificationBus::Handler { friend class EditorTerrainSurfaceDataSystemComponent; TerrainSurfaceDataSystemComponent(const TerrainSurfaceDataSystemConfig&); @@ -58,25 +56,19 @@ namespace SurfaceData ////////////////////////////////////////////////////////////////////////// // SurfaceDataProviderRequestBus - void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const; - - //////////////////////////////////////////////////////////////////////////// - // CrySystemEvents - void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override; - void OnCrySystemShutdown(ISystem& system) override; + void GetSurfacePoints(const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const; ////////////////////////////////////////////////////////////////////////// - // AZ::HeightmapUpdateNotificationBus - void HeightmapModified(const AZ::Aabb& bounds) override; + // AzFramework::Terrain::TerrainDataNotificationBus + void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override; private: void UpdateTerrainData(const AZ::Aabb& dirtyRegion); AZ::Aabb GetSurfaceAabb() const; - SurfaceTagVector GetSurfaceTags() const; - SurfaceDataRegistryHandle m_providerHandle = InvalidSurfaceDataRegistryHandle; + SurfaceData::SurfaceTagVector GetSurfaceTags() const; + SurfaceData::SurfaceDataRegistryHandle m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle; TerrainSurfaceDataSystemConfig m_configuration; - ISystem* m_system = nullptr; AZ::Aabb m_terrainBounds = AZ::Aabb::CreateNull(); AZStd::atomic_bool m_terrainBoundsIsValid{ false }; diff --git a/Tools/LyTestTools/tests/unit/test_builtin_helpers.py b/Tools/LyTestTools/tests/unit/test_builtin_helpers.py index 63dd051a62..9eb8a1703d 100755 --- a/Tools/LyTestTools/tests/unit/test_builtin_helpers.py +++ b/Tools/LyTestTools/tests/unit/test_builtin_helpers.py @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT Unit tests for ly_test_tools.builtin.helpers functions. """ import unittest.mock as mock +import os import pytest @@ -41,6 +42,8 @@ class MockedWorkspaceManager(ly_test_tools._internal.managers.workspace.Abstract ) +@mock.patch('ly_test_tools._internal.managers.abstract_resource_locator._find_project_json', + mock.MagicMock(return_value=os.path.join("mocked", "path"))) @mock.patch( 'ly_test_tools._internal.managers.abstract_resource_locator.AbstractResourceLocator', mock.MagicMock(return_value=MockedAbstractResourceLocator) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 9c142b801c..796e0beb32 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -8,7 +8,6 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 2813ff302e..ff222ee244 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -8,7 +8,6 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 84b042d1b9..e4fcc768c6 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -8,7 +8,6 @@ # shared by other platforms: ly_associate_package(PACKAGE_NAME ilmbase-2.3.0-rev4-multiplatform TARGETS ilmbase PACKAGE_HASH 97547fdf1fbc4d81b8ccf382261f8c25514ed3b3c4f8fd493f0a4fa873bba348) -ly_associate_package(PACKAGE_NAME hdf5-1.0.11-rev2-multiplatform TARGETS hdf5 PACKAGE_HASH 11d5e04df8a93f8c52a5684a4cacbf0d9003056360983ce34f8d7b601082c6bd) ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform TARGETS assimplib PACKAGE_HASH 1a9113788b893ef4a2ee63ac01eb71b981a92894a5a51175703fa225f5804dec) ly_associate_package(PACKAGE_NAME squish-ccr-20150601-rev3-multiplatform TARGETS squish-ccr PACKAGE_HASH c878c6c0c705e78403c397d03f5aa7bc87e5978298710e14d09c9daf951a83b3) ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index e45b7075f0..3d8c32f0f3 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -619,7 +619,7 @@ try { } pipelineProperties.add(disableConcurrentBuilds()) - echo "Running repository: \"${repositoryName}\", pipeline: \"${pipelineName}\", branch: \"${branchName}\"..." + echo "Running repository: \"${repositoryName}\", pipeline: \"${pipelineName}\", branch: \"${branchName}\", CHANGE_ID: \"${env.CHANGE_ID}\", GIT_COMMMIT: \"${scm.GIT_COMMIT}\"..." CheckoutBootstrapScripts(branchName)