diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg
new file mode 100644
index 0000000000..f1d36d3e41
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg
@@ -0,0 +1,7 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg
new file mode 100644
index 0000000000..9fc9fe52c2
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg
@@ -0,0 +1,5 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg
new file mode 100644
index 0000000000..7a61db38e0
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg
@@ -0,0 +1,6 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg
new file mode 100644
index 0000000000..c6fb977c52
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg
@@ -0,0 +1,6 @@
+
diff --git a/Assets/Editor/Translation/scriptcanvas_en_us.ts b/Assets/Editor/Translation/scriptcanvas_en_us.ts
index 937f6a4d96..7b8361c879 100644
--- a/Assets/Editor/Translation/scriptcanvas_en_us.ts
+++ b/Assets/Editor/Translation/scriptcanvas_en_us.ts
@@ -8098,7 +8098,7 @@
COLOR_FROMVALUES_PARAM0_TOOLTIP
- The Red value of hte Color [0, 255]
+ The Red value of the Color [0.0-1.0]
COLOR_FROMVALUES_PARAM1_NAME
@@ -8107,7 +8107,7 @@
COLOR_FROMVALUES_PARAM1_TOOLTIP
- The Green value of the Color [0, 255]
+ The Green value of the Color [0.0-1.0]
COLOR_FROMVALUES_PARAM2_NAME
@@ -8116,7 +8116,7 @@
COLOR_FROMVALUES_PARAM2_TOOLTIP
- The Blue value of the Color [0, 255]
+ The Blue value of the Color [0.0-1.0]
COLOR_FROMVALUES_PARAM3_NAME
@@ -8125,7 +8125,7 @@
COLOR_FROMVALUES_PARAM3_TOOLTIP
- The Alpha value of the Color [0, 255]
+ The Alpha value of the Color [0.0-1.0]
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/README.md b/AutomatedTesting/Gem/PythonTests/AWS/README.md
index 1429fc487f..1bb36f178d 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/README.md
+++ b/AutomatedTesting/Gem/PythonTests/AWS/README.md
@@ -11,7 +11,7 @@
3. Open a new Command Prompt window at the engine root and set the following environment variables:
Set O3DE_AWS_PROJECT_NAME=AWSAUTO
Set O3DE_AWS_DEPLOY_REGION=us-east-1
- Set ASSUME_ROLE_ARN="arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests"
+ Set ASSUME_ROLE_ARN=arn:aws:iam::{your_aws_account_id}:role/o3de-automation-tests
Set COMMIT_ID=HEAD
4. In the same Command Prompt window, Deploy the CDK applications for AWS gems by running deploy_cdk_applications.cmd.
diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
index a0a53f92b5..34b2217916 100644
--- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
+++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py
@@ -31,7 +31,7 @@ def setup(launcher: pytest.fixture,
Set up the resource mapping configuration and start the log monitor.
:param launcher: Client launcher for running the test level.
:param asset_processor: asset_processor fixture.
- :return log monitor object, metrics file path and the metrics stack name.
+ :return log monitor object.
"""
asset_processor.start()
asset_processor.wait_for_idle()
@@ -73,12 +73,11 @@ def monitor_metrics_submission(log_monitor: pytest.fixture) -> None:
f'unexpected_lines values: {unexpected_lines}')
-def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture, stack_name: str) -> None:
+def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings: pytest.fixture) -> None:
"""
Verify that the metrics events are delivered to the S3 bucket and can be queried.
:param aws_metrics_utils: aws_metrics_utils fixture.
:param resource_mappings: resource_mappings fixture.
- :param stack_name: name of the CloudFormation stack.
"""
aws_metrics_utils.verify_s3_delivery(
resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName')
@@ -89,23 +88,24 @@ def query_metrics_from_s3(aws_metrics_utils: pytest.fixture, resource_mappings:
resource_mappings.get_resource_name_id('AWSMetrics.EventsCrawlerName'))
# Remove the events_json table if exists so that the sample query can create a table with the same name.
- aws_metrics_utils.delete_table(f'{stack_name}-eventsdatabase', 'events_json')
- aws_metrics_utils.run_named_queries(f'{stack_name}-AthenaWorkGroup')
+ aws_metrics_utils.delete_table(resource_mappings.get_resource_name_id('AWSMetrics.EventDatabaseName'), 'events_json')
+ aws_metrics_utils.run_named_queries(resource_mappings.get_resource_name_id('AWSMetrics.AthenaWorkGroupName'))
logger.info('Query metrics from S3 successfully.')
-def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: str, start_time: datetime) -> None:
+def verify_operational_metrics(aws_metrics_utils: pytest.fixture,
+ resource_mappings: pytest.fixture, start_time: datetime) -> None:
"""
Verify that operational health metrics are delivered to CloudWatch.
- aws_metrics_utils: aws_metrics_utils fixture.
- stack_name: name of the CloudFormation stack.
- start_time: Time when the game launcher starts.
+ :param aws_metrics_utils: aws_metrics_utils fixture.
+ :param resource_mappings: resource_mappings fixture.
+ :param start_time: Time when the game launcher starts.
"""
aws_metrics_utils.verify_cloud_watch_delivery(
'AWS/Lambda',
'Invocations',
[{'Name': 'FunctionName',
- 'Value': f'{stack_name}-AnalyticsProcessingLambda'}],
+ 'Value': resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsProcessingLambdaName')}],
start_time)
logger.info('AnalyticsProcessingLambda metrics are sent to CloudWatch.')
@@ -113,7 +113,7 @@ def verify_operational_metrics(aws_metrics_utils: pytest.fixture, stack_name: st
'AWS/Lambda',
'Invocations',
[{'Name': 'FunctionName',
- 'Value': f'{stack_name}-EventsProcessingLambda'}],
+ 'Value': resource_mappings.get_resource_name_id('AWSMetrics.EventProcessingLambdaName')}],
start_time)
logger.info('EventsProcessingLambda metrics are sent to CloudWatch.')
@@ -139,7 +139,6 @@ def update_kinesis_analytics_application_status(aws_metrics_utils: pytest.fixtur
@pytest.mark.usefixtures('resource_mappings')
@pytest.mark.parametrize('assume_role_arn', [constants.ASSUME_ROLE_ARN])
@pytest.mark.parametrize('feature_name', [AWS_METRICS_FEATURE_NAME])
-@pytest.mark.parametrize('level', ['AWS/Metrics'])
@pytest.mark.parametrize('profile_name', ['AWSAutomationTest'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('region_name', [constants.AWS_REGION])
@@ -150,6 +149,7 @@ class TestAWSMetricsWindows(object):
"""
Test class to verify the real-time and batch analytics for metrics.
"""
+ @pytest.mark.parametrize('level', ['AWS/Metrics'])
def test_realtime_and_batch_analytics(self,
level: str,
launcher: pytest.fixture,
@@ -157,7 +157,6 @@ class TestAWSMetricsWindows(object):
workspace: pytest.fixture,
aws_utils: pytest.fixture,
resource_mappings: pytest.fixture,
- stacks: typing.List,
aws_metrics_utils: pytest.fixture):
"""
Verify that the metrics events are sent to CloudWatch and S3 for analytics.
@@ -189,10 +188,10 @@ class TestAWSMetricsWindows(object):
operational_threads = list()
operational_threads.append(
AWSMetricsThread(target=query_metrics_from_s3,
- args=(aws_metrics_utils, resource_mappings, stacks[0])))
+ args=(aws_metrics_utils, resource_mappings)))
operational_threads.append(
AWSMetricsThread(target=verify_operational_metrics,
- args=(aws_metrics_utils, stacks[0], start_time)))
+ args=(aws_metrics_utils, resource_mappings, start_time)))
operational_threads.append(
AWSMetricsThread(target=update_kinesis_analytics_application_status,
args=(aws_metrics_utils, resource_mappings, False)))
@@ -201,10 +200,7 @@ class TestAWSMetricsWindows(object):
for thread in operational_threads:
thread.join()
- # Clear the analytics bucket objects so that the S3 bucket can be destroyed during tear down.
- aws_metrics_utils.empty_bucket(
- resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName'))
-
+ @pytest.mark.parametrize('level', ['AWS/Metrics'])
def test_unauthorized_user_request_rejected(self,
level: str,
launcher: pytest.fixture,
@@ -227,3 +223,13 @@ class TestAWSMetricsWindows(object):
halt_on_unexpected=True)
assert result, 'Metrics events are sent successfully by unauthorized user'
logger.info('Unauthorized user is rejected to send metrics.')
+
+ def test_clean_up_s3_bucket(self,
+ aws_utils: pytest.fixture,
+ resource_mappings: pytest.fixture,
+ aws_metrics_utils: pytest.fixture):
+ """
+ Clear the analytics bucket objects so that the S3 bucket can be destroyed during tear down.
+ """
+ aws_metrics_utils.empty_bucket(
+ resource_mappings.get_resource_name_id('AWSMetrics.AnalyticsBucketName'))
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
similarity index 70%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt
rename to AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
index 992420904c..02aaa42597 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
@@ -13,48 +13,56 @@
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS)
ly_add_pytest(
- NAME AutomatedTesting::AtomRenderer_HydraTests_Main
+ NAME AutomatedTesting::Atom_TestSuite_Main
TEST_SUITE main
- PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_MainSuite.py
+ PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
TEST_SERIAL
TIMEOUT 600
RUNTIME_DEPENDENCIES
AssetProcessor
AutomatedTesting.Assets
Editor
+ COMPONENT
+ Atom
)
ly_add_pytest(
- NAME AutomatedTesting::AtomRenderer_HydraTests_Sandbox
+ NAME AutomatedTesting::Atom_TestSuite_Main_Optimized
+ TEST_SUITE main
+ PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
+ TEST_SERIAL
+ TIMEOUT 600
+ RUNTIME_DEPENDENCIES
+ AssetProcessor
+ AutomatedTesting.Assets
+ Editor
+ COMPONENT
+ Atom
+ )
+ ly_add_pytest(
+ NAME AutomatedTesting::Atom_TestSuite_Sandbox
TEST_SUITE sandbox
- PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_SandboxSuite.py
+ PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox.py
TEST_SERIAL
TIMEOUT 400
RUNTIME_DEPENDENCIES
AssetProcessor
AutomatedTesting.Assets
Editor
+ COMPONENT
+ Atom
)
ly_add_pytest(
- NAME AutomatedTesting::AtomRenderer_HydraTests_GPUTests
+ NAME AutomatedTesting::Atom_TestSuite_Main_GPU
TEST_SUITE main
TEST_REQUIRES gpu
TEST_SERIAL
TIMEOUT 1200
- PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_GPUTests.py
- RUNTIME_DEPENDENCIES
- AssetProcessor
- AutomatedTesting.Assets
- Editor
- )
- ly_add_pytest(
- NAME AutomatedTesting::AtomRenderer_HydraTests_ShaderBuildPipeline
- TEST_SUITE main
- PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_ShaderBuildPipelineSuite.py
- TEST_SERIAL
- TIMEOUT 600
+ PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU.py
RUNTIME_DEPENDENCIES
AssetProcessor
AutomatedTesting.Assets
Editor
+ COMPONENT
+ Atom
)
endif()
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
similarity index 94%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py
rename to AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
index 16e281e494..4c5716d365 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_MainSuite.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
@@ -13,10 +13,10 @@ import pytest
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
-from atom_renderer.atom_utils.atom_constants import LIGHT_TYPES
+from Atom.atom_utils.atom_constants import LIGHT_TYPES
logger = logging.getLogger(__name__)
-TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
+TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@@ -38,24 +38,24 @@ class TestAtomEditorComponentsMain(object):
7. Exposure Control
8. Directional Light
9. DepthOfField
- 10. Decal (Atom)
+ 10. Decal
"""
cfg_args = [level]
expected_lines = [
- # Decal (Atom) Component
- "Decal (Atom) Entity successfully created",
- "Decal (Atom)_test: Component added to the entity: True",
- "Decal (Atom)_test: Component removed after UNDO: True",
- "Decal (Atom)_test: Component added after REDO: True",
- "Decal (Atom)_test: Entered game mode: True",
- "Decal (Atom)_test: Exit game mode: True",
- "Decal (Atom) Controller|Configuration|Material: SUCCESS",
- "Decal (Atom)_test: Entity is hidden: True",
- "Decal (Atom)_test: Entity is shown: True",
- "Decal (Atom)_test: Entity deleted: True",
- "Decal (Atom)_test: UNDO entity deletion works: True",
- "Decal (Atom)_test: REDO entity deletion works: True",
+ # Decal Component
+ "Decal Entity successfully created",
+ "Decal_test: Component added to the entity: True",
+ "Decal_test: Component removed after UNDO: True",
+ "Decal_test: Component added after REDO: True",
+ "Decal_test: Entered game mode: True",
+ "Decal_test: Exit game mode: True",
+ "Decal Controller|Configuration|Material: SUCCESS",
+ "Decal_test: Entity is hidden: True",
+ "Decal_test: Entity is shown: True",
+ "Decal_test: Entity deleted: True",
+ "Decal_test: UNDO entity deletion works: True",
+ "Decal_test: REDO entity deletion works: True",
# DepthOfField Component
"DepthOfField Entity successfully created",
"DepthOfField_test: Component added to the entity: True",
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
similarity index 98%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py
rename to AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
index e62ab5e5dc..249b9c7096 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
@@ -3,8 +3,6 @@ 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
-
-Tests that require a GPU in order to run.
"""
import datetime
@@ -22,7 +20,7 @@ import editor_python_test_tools.hydra_test_utils as hydra
logger = logging.getLogger(__name__)
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
-TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
+TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
def golden_images_directory():
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
new file mode 100644
index 0000000000..47b2204d56
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
@@ -0,0 +1,46 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+import pytest
+
+from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
+
+
+@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+class TestAutomation(EditorTestSuite):
+
+ class AtomEditorComponents_DecalAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
+
+ class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
+
+ class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
+
+ class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
+
+ class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
+
+ class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
+
+ class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
+ from Atom.tests import (
+ hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
+
+ class AtomEditorComponents_LightAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
+
+ class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
+
+ class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
+ from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_SandboxSuite.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_SandboxSuite.py
rename to AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/__init__.py b/AutomatedTesting/Gem/PythonTests/Atom/__init__.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/__init__.py
rename to AutomatedTesting/Gem/PythonTests/Atom/__init__.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/__init__.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/__init__.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/__init__.py
rename to AutomatedTesting/Gem/PythonTests/Atom/atom_utils/__init__.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_component_helper.py
rename to AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/atom_constants.py
rename to AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/benchmark_utils.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/benchmark_utils.py
rename to AutomatedTesting/Gem/PythonTests/Atom/atom_utils/benchmark_utils.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/material_editor_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/material_editor_utils.py
rename to AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/screenshot_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/screenshot_utils.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_utils/screenshot_utils.py
rename to AutomatedTesting/Gem/PythonTests/Atom/atom_utils/screenshot_utils.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_1.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_1.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_1.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_1.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_2.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_2.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_2.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_2.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_3.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_3.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_3.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_3.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_4.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_4.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_4.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_4.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_5.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_5.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AreaLight_5.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/AreaLight_5.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AtomBasicLevelSetup.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/AtomBasicLevelSetup.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/AtomBasicLevelSetup.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/AtomBasicLevelSetup.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_1.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_1.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_1.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_1.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_2.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_2.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_2.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_2.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_3.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_3.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_3.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_3.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_4.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_4.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_4.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_4.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_5.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_5.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_5.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_5.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_6.ppm b/AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_6.ppm
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/golden_images/SpotLight_6.ppm
rename to AutomatedTesting/Gem/PythonTests/Atom/golden_images/SpotLight_6.ppm
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/DependencyValidation.azsl.txt b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/DependencyValidation.azsl.txt
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/DependencyValidation.azsl.txt
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/DependencyValidation.azsl.txt
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/DependencyValidation.shader.txt b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/DependencyValidation.shader.txt
similarity index 93%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/DependencyValidation.shader.txt
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/DependencyValidation.shader.txt
index b0eac1783e..4439ec0352 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/DependencyValidation.shader.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/DependencyValidation.shader.txt
@@ -2,7 +2,7 @@
{
"Source" : "DependencyValidation.azsl",
- "DepthStencilState" : {
+ "DepthStencilState" : {
"Depth" : { "Enable" : false, "CompareFunc" : "GreaterEqual" }
},
@@ -22,5 +22,5 @@
}
]
}
-
+
}
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test1Color.azsli.txt b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test1Color.azsli.txt
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test1Color.azsli.txt
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test1Color.azsli.txt
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test2Color.azsli.txt b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test2Color.azsli.txt
similarity index 93%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test2Color.azsli.txt
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test2Color.azsli.txt
index 2ef946b947..565493a0ab 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test2Color.azsli.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test2Color.azsli.txt
@@ -12,5 +12,5 @@
float4 GetTest2Color(float4 color)
{
- return color * 0.5;
+ return color * 0.5;
}
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test3Color.azsli.txt b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test3Color.azsli.txt
similarity index 92%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test3Color.azsli.txt
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test3Color.azsli.txt
index 73b0cca434..7c1ff2be42 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/TestAssets/ShaderAssetBuilder/Test3Color.azsli.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/TestAssets/ShaderAssetBuilder/Test3Color.azsli.txt
@@ -12,5 +12,5 @@
float4 GetTest3Color(float4 color)
{
- return color * 0.13;
+ return color * 0.13;
}
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/__init__.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/__init__.py
similarity index 100%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/__init__.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/__init__.py
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
similarity index 99%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
index a2e950e1dc..602e7564b3 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_AddedToEntity.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
@@ -184,7 +184,7 @@ def run():
material_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
ComponentTests(
- "Decal (Atom)", lambda entity_obj: verify_set_property(
+ "Decal", lambda entity_obj: verify_set_property(
entity_obj, "Controller|Configuration|Material", material_asset))
# Directional Light Component
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py
new file mode 100644
index 0000000000..fa02b75fe2
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py
@@ -0,0 +1,151 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ decal_creation = ("Decal Entity successfully created", "Decal Entity failed to be created")
+ decal_component = ("Entity has a Decal component", "Entity failed to find Decal component")
+ material_property_set = ("Material property set on Decal component", "Couldn't set Material property on Decal component")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_Decal_AddedToEntity():
+ """
+ Summary:
+ Tests the Decal component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Decal entity with no components.
+ 2) Add Decal component to Decal entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Set Material property on Decal component.
+ 9) Delete Decal entity.
+ 10) UNDO deletion.
+ 11) REDO deletion.
+ 12) Look for errors.
+
+ :return: None
+ """
+ import os
+
+ import azlmbr.asset as asset
+ import azlmbr.bus as bus
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Decal entity with no components.
+ decal_name = "Decal"
+ decal_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), decal_name)
+ Report.critical_result(Tests.decal_creation, decal_entity.exists())
+
+ # 2. Add Decal component to Decal entity.
+ decal_component = decal_entity.add_component(decal_name)
+ Report.critical_result(Tests.decal_component, decal_entity.has_component(decal_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not decal_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, decal_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ decal_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, decal_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ decal_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, decal_entity.is_visible() is True)
+
+ # 8. Set Material property on Decal component.
+ decal_material_property_path = "Controller|Configuration|Material"
+ decal_material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
+ decal_material_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", decal_material_asset_path, math.Uuid(), False)
+ decal_component.set_component_property_value(decal_material_property_path, decal_material_asset)
+ get_material_property = decal_component.get_component_property_value(decal_material_property_path)
+ Report.result(Tests.material_property_set, get_material_property == decal_material_asset)
+
+ # 9. Delete Decal entity.
+ decal_entity.delete()
+ Report.result(Tests.entity_deleted, not decal_entity.exists())
+
+ # 10. UNDO deletion.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.deletion_undo, decal_entity.exists())
+
+ # 11. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not decal_entity.exists())
+
+ # 12. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_Decal_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py
new file mode 100644
index 0000000000..80284902ea
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py
@@ -0,0 +1,173 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to Camera entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ camera_property_set = ("DepthOfField Entity set Camera Entity", "DepthOfField Entity could not set Camera Entity")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ depth_of_field_creation = ("DepthOfField Entity successfully created", "DepthOfField Entity failed to be created")
+ depth_of_field_component = ("Entity has a DepthOfField component", "Entity failed to find DepthOfField component")
+ depth_of_field_disabled = ("DepthOfField component disabled", "DepthOfField component was not disabled.")
+ post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component")
+ depth_of_field_enabled = ("DepthOfField component enabled", "DepthOfField component was not enabled.")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_DepthOfField_AddedToEntity():
+ """
+ Summary:
+ Tests the DepthOfField component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a DepthOfField entity with no components.
+ 2) Add a DepthOfField component to DepthOfField entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Verify DepthOfField component not enabled.
+ 6) Add Post FX Layer component since it is required by the DepthOfField component.
+ 7) Verify DepthOfField component is enabled.
+ 8) Enter/Exit game mode.
+ 9) Test IsHidden.
+ 10) Test IsVisible.
+ 11) Add Camera entity.
+ 12) Add Camera component to Camera entity.
+ 13) Set the DepthOfField components's Camera Entity to the newly created Camera entity.
+ 14) Delete DepthOfField entity.
+ 15) UNDO deletion.
+ 16) REDO deletion.
+ 17) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a DepthOfField entity with no components.
+ depth_of_field_name = "DepthOfField"
+ depth_of_field_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(512.0, 512.0, 34.0), depth_of_field_name)
+ Report.critical_result(Tests.depth_of_field_creation, depth_of_field_entity.exists())
+
+ # 2. Add a DepthOfField component to DepthOfField entity.
+ depth_of_field_component = depth_of_field_entity.add_component(depth_of_field_name)
+ Report.critical_result(Tests.depth_of_field_component, depth_of_field_entity.has_component(depth_of_field_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not depth_of_field_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, depth_of_field_entity.exists())
+
+ # 5. Verify DepthOfField component not enabled.
+ Report.result(Tests.depth_of_field_disabled, not depth_of_field_component.is_enabled())
+
+ # 6. Add Post FX Layer component since it is required by the DepthOfField component.
+ post_fx_layer = "PostFX Layer"
+ depth_of_field_entity.add_component(post_fx_layer)
+ Report.result(Tests.post_fx_component, depth_of_field_entity.has_component(post_fx_layer))
+
+ # 7. Verify DepthOfField component is enabled.
+ Report.result(Tests.depth_of_field_enabled, depth_of_field_component.is_enabled())
+
+ # 8. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 9. Test IsHidden.
+ depth_of_field_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, depth_of_field_entity.is_hidden() is True)
+
+ # 10. Test IsVisible.
+ depth_of_field_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, depth_of_field_entity.is_visible() is True)
+
+ # 11. Add Camera entity.
+ camera_name = "Camera"
+ camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name)
+ Report.result(Tests.camera_creation, camera_entity.exists())
+
+ # 12. Add Camera component to Camera entity.
+ camera_entity.add_component(camera_name)
+ Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
+
+ # 13. Set the DepthOfField components's Camera Entity to the newly created Camera entity.
+ depth_of_field_camera_property_path = "Controller|Configuration|Camera Entity"
+ depth_of_field_component.set_component_property_value(depth_of_field_camera_property_path, camera_entity.id)
+ camera_entity_set = depth_of_field_component.get_component_property_value(depth_of_field_camera_property_path)
+ Report.result(Tests.camera_property_set, camera_entity.id == camera_entity_set)
+
+ # 14. Delete DepthOfField entity.
+ depth_of_field_entity.delete()
+ Report.result(Tests.entity_deleted, not depth_of_field_entity.exists())
+
+ # 15. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, depth_of_field_entity.exists())
+
+ # 16. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not depth_of_field_entity.exists())
+
+ # 17. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_DepthOfField_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py
new file mode 100644
index 0000000000..048e132df4
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py
@@ -0,0 +1,157 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ directional_light_creation = ("Directional Light Entity successfully created", "Directional Light Entity failed to be created")
+ directional_light_component = ("Entity has a Directional Light component", "Entity failed to find Directional Light component")
+ shadow_camera_check = ("Directional Light component Shadow camera set", "Directional Light component Shadow camera was not set")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_DirectionalLight_AddedToEntity():
+ """
+ Summary:
+ Tests the Directional Light component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Directional Light entity with no components.
+ 2) Add Directional Light component to Directional Light entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Add Camera entity.
+ 9) Add Camera component to Camera entity
+ 10) Set the Directional Light component property Shadow|Camera to the Camera entity.
+ 11) Delete Directional Light entity.
+ 12) UNDO deletion.
+ 13) REDO deletion.
+ 14) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Directional Light entity with no components.
+ directional_light_name = "Directional Light"
+ directional_light_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(512.0, 512.0, 34.0), directional_light_name)
+ Report.critical_result(Tests.directional_light_creation, directional_light_entity.exists())
+
+ # 2. Add Directional Light component to Directional Light entity.
+ directional_light_component = directional_light_entity.add_component(directional_light_name)
+ Report.critical_result(
+ Tests.directional_light_component, directional_light_entity.has_component(directional_light_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not directional_light_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, directional_light_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ directional_light_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, directional_light_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ directional_light_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, directional_light_entity.is_visible() is True)
+
+ # 8. Add Camera entity.
+ camera_name = "Camera"
+ camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name)
+ Report.result(Tests.camera_creation, camera_entity.exists())
+
+ # 9. Add Camera component to Camera entity.
+ camera_entity.add_component(camera_name)
+ Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
+
+ # 10. Set the Directional Light component property Shadow|Camera to the Camera entity.
+ shadow_camera_property_path = "Controller|Configuration|Shadow|Camera"
+ directional_light_component.set_component_property_value(shadow_camera_property_path, camera_entity.id)
+ shadow_camera_set = directional_light_component.get_component_property_value(shadow_camera_property_path)
+ Report.result(Tests.shadow_camera_check, camera_entity.id == shadow_camera_set)
+
+ # 11. Delete DirectionalLight entity.
+ directional_light_entity.delete()
+ Report.result(Tests.entity_deleted, not directional_light_entity.exists())
+
+ # 12. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, directional_light_entity.exists())
+
+ # 13. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not directional_light_entity.exists())
+
+ # 14. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_DirectionalLight_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py
new file mode 100644
index 0000000000..39d7acf4f4
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py
@@ -0,0 +1,137 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ display_mapper_creation = ("Display Mapper Entity successfully created", "Display Mapper Entity failed to be created")
+ display_mapper_component = ("Entity has a Display Mapper component", "Entity failed to find Display Mapper component")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_DisplayMapper_AddedToEntity():
+ """
+ Summary:
+ Tests the Display Mapper component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Display Mapper entity with no components.
+ 2) Add Display Mapper component to Display Mapper entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Delete Display Mapper entity.
+ 9) UNDO deletion.
+ 10) REDO deletion.
+ 11) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Display Mapper entity with no components.
+ display_mapper = "Display Mapper"
+ display_mapper_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(512.0, 512.0, 34.0), f"{display_mapper}")
+ Report.critical_result(Tests.display_mapper_creation, display_mapper_entity.exists())
+
+ # 2. Add Display Mapper component to Display Mapper entity.
+ display_mapper_entity.add_component(display_mapper)
+ Report.critical_result(Tests.display_mapper_component, display_mapper_entity.has_component(display_mapper))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not display_mapper_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, display_mapper_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ display_mapper_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, display_mapper_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ display_mapper_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, display_mapper_entity.is_visible() is True)
+
+ # 8. Delete Display Mapper entity.
+ display_mapper_entity.delete()
+ Report.result(Tests.entity_deleted, not display_mapper_entity.exists())
+
+ # 9. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, display_mapper_entity.exists())
+
+ # 10. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
+
+ # 11. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_DisplayMapper_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py
new file mode 100644
index 0000000000..23a84435f7
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py
@@ -0,0 +1,145 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ exposure_control_creation = ("ExposureControl Entity successfully created", "ExposureControl Entity failed to be created")
+ exposure_control_component = ("Entity has a Exposure Control component", "Entity failed to find Exposure Control component")
+ post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_ExposureControl_AddedToEntity():
+ """
+ Summary:
+ Tests the Exposure Control component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create an Exposure Control entity with no components.
+ 2) Add Exposure Control component to Exposure Control entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Add Post FX Layer component.
+ 9) Delete Exposure Control entity.
+ 10) UNDO deletion.
+ 11) REDO deletion.
+ 12) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Creation of Exposure Control entity with no components.
+ exposure_control_name = "Exposure Control"
+ exposure_control_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(512.0, 512.0, 34.0), f"{exposure_control_name}")
+ Report.critical_result(Tests.exposure_control_creation, exposure_control_entity.exists())
+
+ # 2. Add Exposure Control component to Exposure Control entity.
+ exposure_control_entity.add_component(exposure_control_name)
+ Report.critical_result(
+ Tests.exposure_control_component, exposure_control_entity.has_component(exposure_control_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not exposure_control_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, exposure_control_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ exposure_control_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, exposure_control_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ exposure_control_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, exposure_control_entity.is_visible() is True)
+
+ # 8. Add Post FX Layer component.
+ post_fx_layer_name = "PostFX Layer"
+ exposure_control_entity.add_component(post_fx_layer_name)
+ Report.result(Tests.post_fx_component, exposure_control_entity.has_component(post_fx_layer_name))
+
+ # 9. Delete ExposureControl entity.
+ exposure_control_entity.delete()
+ Report.result(Tests.entity_deleted, not exposure_control_entity.exists())
+
+ # 10. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, exposure_control_entity.exists())
+
+ # 11. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not exposure_control_entity.exists())
+
+ # 12. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_ExposureControl_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py
new file mode 100644
index 0000000000..cc891f5929
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py
@@ -0,0 +1,164 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ global_skylight_creation = ("Global Skylight (IBL) Entity successfully created", "Global Skylight (IBL) Entity failed to be created")
+ global_skylight_component = ("Entity has a Global Skylight (IBL) component", "Entity failed to find Global Skylight (IBL) component")
+ diffuse_image_set = ("Entity has the Diffuse Image set", "Entity did not the Diffuse Image set")
+ specular_image_set = ("Entity has the Specular Image set", "Entity did not the Specular Image set")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
+ """
+ Summary:
+ Tests the Global Skylight (IBL) component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Global Skylight (IBL) entity with no components.
+ 2) Add Global Skylight (IBL) component to Global Skylight (IBL) entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Add Post FX Layer component.
+ 9) Add Camera component
+ 10) Delete Global Skylight (IBL) entity.
+ 11) UNDO deletion.
+ 12) REDO deletion.
+ 13) Look for errors.
+
+ :return: None
+ """
+ import os
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.asset_utils import Asset
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Global Skylight (IBL) entity with no components.
+ global_skylight_name = "Global Skylight (IBL)"
+ global_skylight_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(512.0, 512.0, 34.0), global_skylight_name)
+ Report.critical_result(Tests.global_skylight_creation, global_skylight_entity.exists())
+
+ # 2. Add Global Skylight (IBL) component to Global Skylight (IBL) entity.
+ global_skylight_component = global_skylight_entity.add_component(global_skylight_name)
+ Report.critical_result(
+ Tests.global_skylight_component, global_skylight_entity.has_component(global_skylight_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not global_skylight_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, global_skylight_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ global_skylight_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, global_skylight_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ global_skylight_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, global_skylight_entity.is_visible() is True)
+
+ # 8. Set the Diffuse Image asset on the Global Skylight (IBL) entity.
+ global_skylight_diffuse_image_property = "Controller|Configuration|Diffuse Image"
+ diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
+ diffuse_image_asset = Asset.find_asset_by_path(diffuse_image_path, False)
+ global_skylight_component.set_component_property_value(
+ global_skylight_diffuse_image_property, diffuse_image_asset.id)
+ diffuse_image_set = global_skylight_component.get_component_property_value(
+ global_skylight_diffuse_image_property)
+ Report.result(Tests.diffuse_image_set, diffuse_image_set == diffuse_image_asset.id)
+
+ # 9. Set the Specular Image asset on the Global Light (IBL) entity.
+ global_skylight_specular_image_property = "Controller|Configuration|Specular Image"
+ specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
+ specular_image_asset = Asset.find_asset_by_path(specular_image_path, False)
+ global_skylight_component.set_component_property_value(
+ global_skylight_specular_image_property, specular_image_asset.id)
+ specular_image_added = global_skylight_component.get_component_property_value(
+ global_skylight_specular_image_property)
+ Report.result(Tests.specular_image_set, specular_image_added == specular_image_asset.id)
+
+ # 10. Delete Global Skylight (IBL) entity.
+ global_skylight_entity.delete()
+ Report.result(Tests.entity_deleted, not global_skylight_entity.exists())
+
+ # 11. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, global_skylight_entity.exists())
+
+ # 12. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not global_skylight_entity.exists())
+
+ # 13. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_GlobalSkylightIBL_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py
new file mode 100644
index 0000000000..8b1432f1f7
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py
@@ -0,0 +1,136 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ light_creation = ("Light Entity successfully created", "Light Entity failed to be created")
+ light_component = ("Entity has a Light component", "Entity failed to find Light component")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_Light_AddedToEntity():
+ """
+ Summary:
+ Tests the Light component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Light entity with no components.
+ 2) Add Light component to the Light entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Delete Light entity.
+ 9) UNDO deletion.
+ 10) REDO deletion.
+ 11) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Light entity with no components.
+ light_name = "Light"
+ light_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), light_name)
+ Report.critical_result(Tests.light_creation, light_entity.exists())
+
+ # 2. Add Light component to the Light entity.
+ light_entity.add_component(light_name)
+ Report.critical_result(Tests.light_component, light_entity.has_component(light_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not light_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, light_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ light_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, light_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ light_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, light_entity.is_visible() is True)
+
+ # 8. Delete Light entity.
+ light_entity.delete()
+ Report.result(Tests.entity_deleted, not light_entity.exists())
+
+ # 9. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, light_entity.exists())
+
+ # 10. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not light_entity.exists())
+
+ # 11. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_Light_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py
similarity index 95%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py
index 8d138e67b8..751f425916 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomEditorComponents_LightComponent.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py
@@ -1,10 +1,8 @@
"""
-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.
+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
-
-Hydra script that creates an entity, attaches the Light component to it for test verifications.
-The test verifies that each light type option is available and can be selected without errors.
"""
import os
@@ -19,7 +17,7 @@ import azlmbr.legacy.general as general
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
-from atom_renderer.atom_utils.atom_constants import LIGHT_TYPES
+from Atom.atom_utils.atom_constants import LIGHT_TYPES
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py
new file mode 100644
index 0000000000..04441d5b2c
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py
@@ -0,0 +1,136 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ physical_sky_creation = ("Physical Sky Entity successfully created", "Physical Sky Entity failed to be created")
+ physical_sky_component = ("Entity has a Physical Sky component", "Entity failed to find Physical Sky component")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_PhysicalSky_AddedToEntity():
+ """
+ Summary:
+ Tests the Physical Sky component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Physical Sky entity with no components.
+ 2) Add Physical Sky component to Physical Sky entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Delete Physical Sky entity.
+ 9) UNDO deletion.
+ 10) REDO deletion.
+ 11) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Physical Sky entity with no components.
+ physical_sky_name = "Physical Sky"
+ physical_sky_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), physical_sky_name)
+ Report.critical_result(Tests.physical_sky_creation, physical_sky_entity.exists())
+
+ # 2. Add Physical Sky component to Physical Sky entity.
+ physical_sky_entity.add_component(physical_sky_name)
+ Report.critical_result(Tests.physical_sky_component, physical_sky_entity.has_component(physical_sky_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not physical_sky_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, physical_sky_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ physical_sky_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, physical_sky_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ physical_sky_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, physical_sky_entity.is_visible() is True)
+
+ # 8. Delete Physical Sky entity.
+ physical_sky_entity.delete()
+ Report.result(Tests.entity_deleted, not physical_sky_entity.exists())
+
+ # 9. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, physical_sky_entity.exists())
+
+ # 10. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not physical_sky_entity.exists())
+
+ # 11. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_PhysicalSky_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py
new file mode 100644
index 0000000000..8914ab9e7e
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py
@@ -0,0 +1,138 @@
+"""
+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
+"""
+
+# fmt: off
+class Tests:
+ camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created")
+ camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity")
+ camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component")
+ creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed")
+ creation_redo = ("REDO Entity creation success", "REDO Entity creation failed")
+ postfx_radius_weight_creation = ("PostFX Radius Weight Modifier Entity successfully created", "PostFX Radius Weight Modifier Entity failed to be created")
+ postfx_radius_weight_component = ("Entity has a PostFX Radius Weight Modifier component", "Entity failed to find PostFX Radius Weight Modifier component")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ is_visible = ("Entity is visible", "Entity was not visible")
+ is_hidden = ("Entity is hidden", "Entity was not hidden")
+ entity_deleted = ("Entity deleted", "Entity was not deleted")
+ deletion_undo = ("UNDO deletion success", "UNDO deletion failed")
+ deletion_redo = ("REDO deletion success", "REDO deletion failed")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
+
+
+def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity():
+ """
+ Summary:
+ Tests the PostFX Radius Weight Modifier component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Post FX Radius Weight Modifier entity with no components.
+ 2) Add Post FX Radius Weight Modifier component to Post FX Radius Weight Modifier entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Delete PostFX Radius Weight Modifier entity.
+ 9) UNDO deletion.
+ 10) REDO deletion.
+ 11) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ helper.init_idle()
+ helper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a Post FX Radius Weight Modifier entity with no components.
+ postfx_radius_weight_name = "PostFX Radius Weight Modifier"
+ postfx_radius_weight_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(512.0, 512.0, 34.0), postfx_radius_weight_name)
+ Report.critical_result(Tests.postfx_radius_weight_creation, postfx_radius_weight_entity.exists())
+
+ # 2. Add Post FX Radius Weight Modifier component to Post FX Radius Weight Modifier entity.
+ postfx_radius_weight_entity.add_component(postfx_radius_weight_name)
+ Report.critical_result(
+ Tests.postfx_radius_weight_component, postfx_radius_weight_entity.has_component(postfx_radius_weight_name))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not postfx_radius_weight_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, postfx_radius_weight_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ postfx_radius_weight_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, postfx_radius_weight_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ postfx_radius_weight_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, postfx_radius_weight_entity.is_visible() is True)
+
+ # 8. Delete PostFX Radius Weight Modifier entity.
+ postfx_radius_weight_entity.delete()
+ Report.result(Tests.entity_deleted, not postfx_radius_weight_entity.exists())
+
+ # 9. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, postfx_radius_weight_entity.exists())
+
+ # 10. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not postfx_radius_weight_entity.exists())
+
+ # 11. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomMaterialEditor_BasicTests.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
similarity index 95%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomMaterialEditor_BasicTests.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
index 9047b4c871..88a1ef4c7b 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_AtomMaterialEditor_BasicTests.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
@@ -3,12 +3,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
-
-import azlmbr.materialeditor will fail with a ModuleNotFound error when using this script with Editor.exe
-This is because azlmbr.materialeditor only binds to MaterialEditor.exe and not Editor.exe
-You need to launch this script with MaterialEditor.exe in order for azlmbr.materialeditor to appear.
"""
+# import azlmbr.materialeditor will fail with a ModuleNotFound error when using this script with Editor.exe
+# This is because azlmbr.materialeditor only binds to MaterialEditor.exe and not Editor.exe
+# You need to launch this script with MaterialEditor.exe in order for azlmbr.materialeditor to appear.
+
import os
import sys
import time
@@ -18,7 +18,7 @@ import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
-import atom_renderer.atom_utils.material_editor_utils as material_editor
+import Atom.atom_utils.material_editor_utils as material_editor
NEW_MATERIAL = "test_material.material"
NEW_MATERIAL_1 = "test_material_1.material"
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
similarity index 92%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
index 3aa9fe660c..4f7edeba75 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
@@ -3,11 +3,6 @@ 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
-
-Hydra script that is used to create a new level with a default rendering setup.
-After the level is setup, screenshots are diffed against golden images are used to verify pass/fail results of the test.
-
-See the run() function for more in-depth test info.
"""
import os
@@ -19,7 +14,7 @@ sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "P
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper
-from atom_renderer.atom_utils.benchmark_utils import BenchmarkHelper
+from Atom.atom_utils.benchmark_utils import BenchmarkHelper
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
similarity index 97%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_BasicLevelSetup.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
index 920c044be0..62a122a723 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_BasicLevelSetup.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
@@ -3,11 +3,6 @@ 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
-
-Hydra script that is used to create a new level with a default rendering setup.
-After the level is setup, screenshots are diffed against golden images are used to verify pass/fail results of the test.
-
-See the run() function for more in-depth test info.
"""
import os
@@ -26,7 +21,7 @@ sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "P
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper
-from atom_renderer.atom_utils.screenshot_utils import ScreenshotHelper
+from Atom.atom_utils.screenshot_utils import ScreenshotHelper
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
similarity index 97%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
index 8063445608..4a3ae8c85d 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_GPUTest_LightComponent.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
@@ -3,12 +3,6 @@ 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
-
-Hydra script that is used to create an entity with a Light component attached.
-It then updates the property values of the Light component and takes a screenshot.
-The screenshot is compared against an expected golden image for test verification.
-
-See the run() function for more in-depth test info.
"""
import os
import sys
@@ -23,7 +17,7 @@ import azlmbr.legacy.general as general
sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
-from atom_renderer.atom_utils import atom_component_helper, atom_constants, screenshot_utils
+from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges.py
similarity index 60%
rename from AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges.py
rename to AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges.py
index a05420d960..f13227aa9d 100644
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/atom_hydra_scripts/hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges.py
@@ -3,78 +3,19 @@ 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 shutil
-
-def _copy_file(src_file, src_path, target_file, target_path):
- # type: (str, str, str, str) -> None
- """
- Copies the [src_file] located in [src_path] to the [target_file] located at [target_path].
- Leaves the [target_file] unlocked for reading and writing privileges
- :param src_file: The source file to copy (file name)
- :param src_path: The source file's path
- :param target_file: The target file to copy into (file name)
- :param target_path: The target file's path
- :return: None
- """
- target_file_path = os.path.join(target_path, target_file)
- src_file_path = os.path.join(src_path, src_file)
- if os.path.exists(target_file_path):
- fs.unlock_file(target_file_path)
- shutil.copyfile(src_file_path, target_file_path)
-
-def _copy_tmp_files_in_order(src_directory, file_list, dst_directory, wait_time_in_between = 0.0):
- # type: (str, list, str, float) -> None
- """
- This function assumes that for each file name listed in @file_list
- there's file named "@filename.txt" which the original source file
- but they will be copied with just the @filename (.txt removed).
- """
- for filename in file_list:
- src_name = f"{filename}.txt"
- _copy_file(src_name, src_directory, filename, dst_directory)
- if wait_time_in_between > 0.0:
- print(f"Created {filename} in {dst_directory}")
- general.idle_wait(wait_time_in_between)
-
-
-def _remove_file(src_file, src_path):
- # type: (str, str) -> None
- """
- Removes the [src_file] located in [src_path].
- :param src_file: The source file to copy (file name)
- :param src_path: The source file's path
- :return: None
- """
- src_file_path = os.path.join(src_path, src_file)
- if os.path.exists(src_file_path):
- fs.unlock_file(src_file_path)
- os.remove(src_file_path)
-
-
-def _remove_files(directory, file_list):
- for filename in file_list:
- _remove_file(filename, directory)
-
-
-def _asset_exists(cache_relative_path):
- asset_id = azasset.AssetCatalogRequestBus(azbus.Broadcast, "GetAssetIdByPath", cache_relative_path, azmath.Uuid(), False)
- return asset_id.is_valid()
-
-# List of results that we want to check, this is not 100% necessary but it's a good
-# practice to make it easier to debug tests.
-# Here we define a tuple of tests
-class Results():
- azshader_was_removed = ("azshader was removed", "Failed to remove azshader")
- azshader_was_compiled = ("azshader was compiled", "Failed to compile azshader")
+# fmt: off
+class Tests():
+ azshader_was_removed = ("azshader was removed", "Failed to remove azshader")
+ azshader_was_compiled = ("azshader was compiled", "Failed to compile azshader")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+# fmt: on
def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
"""
- This test validates [ATOM-5441] Shader Builders May Fail When Multiple New Files Are Added
+ This test validates: "Shader Builders May Fail When Multiple New Files Are Added"
It creates source assets to compile a particular shader.
1- The first phase generates the source assets out of order and slowly. The AP should
wakeup each time one of the source dependencies appears but will fail each time. Only when the
@@ -82,6 +23,71 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
2- The second phase is similar as above, except that all source assets will be created
at once and We also expect that in the end the shader is built successfully.
"""
+ import os
+ import shutil
+
+ import azlmbr.asset as azasset
+ import azlmbr.bus as azbus
+ import azlmbr.legacy.general as general
+ import azlmbr.math as azmath
+
+ from editor_python_test_tools.utils import TestHelper as helper
+ from editor_python_test_tools.utils import Tracer
+ import ly_test_tools.environment.file_system as fs
+
+ def _copy_file(src_file, src_path, target_file, target_path):
+ # type: (str, str, str, str) -> None
+ """
+ Copies the [src_file] located in [src_path] to the [target_file] located at [target_path].
+ Leaves the [target_file] unlocked for reading and writing privileges
+ :param src_file: The source file to copy (file name)
+ :param src_path: The source file's path
+ :param target_file: The target file to copy into (file name)
+ :param target_path: The target file's path
+ :return: None
+ """
+ target_file_path = os.path.join(target_path, target_file)
+ src_file_path = os.path.join(src_path, src_file)
+ if os.path.exists(target_file_path):
+ fs.unlock_file(target_file_path)
+ shutil.copyfile(src_file_path, target_file_path)
+
+ def _copy_tmp_files_in_order(src_directory, file_list, dst_directory, wait_time_in_between=0.0):
+ # type: (str, list, str, float) -> None
+ """
+ This function assumes that for each file name listed in @file_list
+ there's file named "@filename.txt" which the original source file
+ but they will be copied with just the @filename (.txt removed).
+ """
+ for filename in file_list:
+ src_name = f"{filename}.txt"
+ _copy_file(src_name, src_directory, filename, dst_directory)
+ if wait_time_in_between > 0.0:
+ print(f"Created {filename} in {dst_directory}")
+ general.idle_wait(wait_time_in_between)
+
+ def _remove_file(src_file, src_path):
+ # type: (str, str) -> None
+ """
+ Removes the [src_file] located in [src_path].
+ :param src_file: The source file to copy (file name)
+ :param src_path: The source file's path
+ :return: None
+ """
+ src_file_path = os.path.join(src_path, src_file)
+ if os.path.exists(src_file_path):
+ fs.unlock_file(src_file_path)
+ os.remove(src_file_path)
+
+ def _remove_files(directory, file_list):
+ for filename in file_list:
+ _remove_file(filename, directory)
+
+ def _asset_exists(cache_relative_path):
+ asset_id = azasset.AssetCatalogRequestBus(azbus.Broadcast, "GetAssetIdByPath", cache_relative_path,
+ azmath.Uuid(), False)
+ return asset_id.is_valid()
+
# Required for automated tests
helper.init_idle()
@@ -115,14 +121,14 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
azshader_name = "assets/dependencyvalidation.azshader"
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
- Report.critical_result(Results.azshader_was_removed, not _asset_exists(azshader_name))
+ Report.critical_result(Tests.azshader_was_removed, not _asset_exists(azshader_name))
_copy_tmp_files_in_order(src_assets_subdir, file_list, game_asset_path, 1.0)
# Give enough time to AP to compile the shader
helper.wait_for_condition(lambda: _asset_exists(azshader_name), 60.0)
- Report.critical_result(Results.azshader_was_compiled, _asset_exists(azshader_name))
+ Report.critical_result(Tests.azshader_was_compiled, _asset_exists(azshader_name))
# The first part was about compiling the shader under normal conditions.
# Let's remove the files from the previous phase and will proceed
@@ -130,7 +136,7 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
# ShaderAssetBuilder will only succeed when the last file becomes visible.
_remove_files(game_asset_path, reverse_file_list)
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
- Report.critical_result(Results.azshader_was_removed, not _asset_exists(azshader_name))
+ Report.critical_result(Tests.azshader_was_removed, not _asset_exists(azshader_name))
# Remark, if you are running this test manually from the Editor with "pyRunFile",
# You'll notice how the AP issues notifications that it fails to compile the shader
@@ -148,7 +154,7 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
# Give enough time to AP to compile the shader
helper.wait_for_condition(lambda: _asset_exists(azshader_name), 60.0)
- Report.critical_result(Results.azshader_was_compiled, _asset_exists(azshader_name))
+ Report.critical_result(Tests.azshader_was_compiled, _asset_exists(azshader_name))
# The last phase of the test puts stress on potential race conditions
# when all required files appear as soon as possible.
@@ -157,7 +163,7 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
# Remove left over files.
_remove_files(game_asset_path, reverse_file_list)
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
- Report.critical_result(Results.azshader_was_removed, not _asset_exists(azshader_name))
+ Report.critical_result(Tests.azshader_was_removed, not _asset_exists(azshader_name))
# Now let's copy all the source files to the "Assets" folder as fast as possible.
_copy_tmp_files_in_order(src_assets_subdir, reverse_file_list, game_asset_path)
@@ -165,24 +171,17 @@ def ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges():
# Give enough time to AP to compile the shader
helper.wait_for_condition(lambda: _asset_exists(azshader_name), 60.0)
- Report.critical_result(Results.azshader_was_compiled, _asset_exists(azshader_name))
+ Report.critical_result(Tests.azshader_was_compiled, _asset_exists(azshader_name))
# All good, let's cleanup leftover files before closing the test.
_remove_files(game_asset_path, reverse_file_list)
helper.wait_for_condition(lambda: not _asset_exists(azshader_name), 5.0)
+ # Look for errors to raise.
+ helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
if __name__ == "__main__":
- # All exposed python bindings are in azlmbr
- import azlmbr.legacy.general as general
- import azlmbr.bus as azbus
- import azlmbr.asset as azasset
- import azlmbr.math as azmath
-
- # Import report and test helper utilities
from editor_python_test_tools.utils import Report
- from editor_python_test_tools.utils import TestHelper as helper
- from editor_python_test_tools.utils import Tracer
- import ly_test_tools.environment.file_system as fs
-
- Report.start_test(ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges)
\ No newline at end of file
+ Report.start_test(ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges)
diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
index 7fd3b3a241..466a4b1679 100644
--- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
@@ -18,7 +18,7 @@ include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
add_subdirectory(assetpipeline)
## Atom Renderer ##
-add_subdirectory(atom_renderer)
+add_subdirectory(Atom)
## Physics ##
add_subdirectory(Physics)
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
index fec9d9880b..154b5730d7 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
@@ -20,6 +20,7 @@ import azlmbr.legacy.general as general
# Helper file Imports
from editor_python_test_tools.utils import Report
+
class EditorComponent:
"""
EditorComponent class used to set and get the component property value using path
@@ -28,7 +29,6 @@ class EditorComponent:
which also assigns self.id and self.type_id to the EditorComponent object.
"""
- # Methods
def get_component_name(self) -> str:
"""
Used to get name of component
@@ -87,6 +87,13 @@ class EditorComponent:
outcome.IsSuccess()
), f"Failure: Could not set value to '{self.get_component_name()}' : '{component_property_path}'"
+ def is_enabled(self):
+ """
+ Used to verify if the component is enabled.
+ :return: True if enabled, otherwise False.
+ """
+ return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", self.id)
+
@staticmethod
def get_type_ids(component_names: list) -> list:
"""
@@ -254,7 +261,7 @@ class EditorEntity:
def get_components_of_type(self, component_names: list) -> List[EditorComponent]:
"""
Used to get components of type component_name that already exists on Entity
- :param component_name: Name to component to check
+ :param component_names: List of names of components to check
:return: List of Entity Component objects of given component name
"""
component_list = []
@@ -318,3 +325,39 @@ class EditorEntity:
editor.EditorEntityAPIBus(bus.Event, "SetStartStatus", self.id, status_to_set)
set_status = self.get_start_status()
assert set_status == status_to_set, f"Failed to set start status of {desired_start_status} to {self.get_name}"
+
+ def delete(self) -> None:
+ """
+ Used to delete the Entity.
+ :return: None
+ """
+ editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", self.id)
+
+ def set_visibility_state(self, is_visible: bool) -> None:
+ """
+ Sets the visibility state on the object to visible or not visible.
+ :param is_visible: True for making visible, False to make not visible.
+ :return: None
+ """
+ editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", self.id, is_visible)
+
+ def exists(self) -> bool:
+ """
+ Used to verify if the Entity exists.
+ :return: True if the Entity exists, False otherwise.
+ """
+ return editor.ToolsApplicationRequestBus(bus.Broadcast, "EntityExists", self.id)
+
+ def is_hidden(self) -> bool:
+ """
+ Gets the "isHidden" value from the Entity.
+ :return: True if "isHidden" is enabled, False otherwise.
+ """
+ return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", self.id)
+
+ def is_visible(self) -> bool:
+ """
+ Gets the "isVisible" value from the Entity.
+ :return: True if "isVisible" is enabled, False otherwise.
+ """
+ return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id)
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_test_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_test_utils.py
index 3d4d9ea419..54bc118f48 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_test_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_test_utils.py
@@ -81,7 +81,8 @@ def launch_and_validate_results(request, test_directory, editor, editor_script,
def launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines, null_renderer=True,
- port_listener_timeout=120, log_monitor_timeout=300, remote_console_port=4600):
+ port_listener_timeout=120, log_monitor_timeout=300, remote_console_port=4600,
+ launch_ap=True):
"""
Runs the launcher with the specified level, and monitors Game.log for expected lines.
:param launcher: Configured launcher object to run test against.
@@ -92,6 +93,7 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
:param port_listener_timeout: Timeout for verifying successful connection to Remote Console.
:param log_monitor_timeout: Timeout for monitoring for lines in Game.log
:param remote_console_port: The port used to communicate with the Remote Console.
+ :param launch_ap: Whether or not to launch AP. Defaults to True.
"""
def _check_for_listening_port(port):
@@ -110,7 +112,7 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
launcher.args.extend(["-rhi=Null"])
# Start the Launcher
- with launcher.start():
+ with launcher.start(launch_ap=launch_ap):
# Ensure Remote Console can be reached
waiter.wait_for(
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt
index 4a26500ee2..52682e70bb 100644
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/CMakeLists.txt
@@ -17,5 +17,14 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
AZ::AssetProcessorBatch
AZ::AssetProcessor
)
+
+ ly_add_pytest(
+ NAME AssetPipelineTests.Fbx_Tests
+ PATH ${CMAKE_CURRENT_LIST_DIR}/fbx_test/fbx_test.py
+ TEST_SUITE sandbox
+ RUNTIME_DEPENDENCIES
+ AZ::AssetProcessorBatch
+ AZ::AssetProcessor
+ )
endif()
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py
index 2b90f53fc3..5cb61da68e 100755
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py
@@ -34,11 +34,13 @@ logger = logging.getLogger(__name__)
targetProjects = ["AutomatedTesting"]
@pytest.fixture
+@pytest.mark.SUITE_sandbox
def local_resources(request, workspace, ap_setup_fixture):
ap_setup_fixture["tests_dir"] = os.path.dirname(os.path.realpath(__file__))
@dataclass
+@pytest.mark.SUITE_sandbox
class BlackboxAssetTest:
test_name: str
asset_folder: str
@@ -338,9 +340,11 @@ blackbox_fbx_special_tests = [
@pytest.mark.usefixtures("local_resources")
@pytest.mark.parametrize("project", targetProjects)
@pytest.mark.assetpipeline
+@pytest.mark.SUITE_sandbox
class TestsFBX_AllPlatforms(object):
@pytest.mark.BAT
+ @pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests)
def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace,
ap_setup_fixture, asset_processor, project,
@@ -359,6 +363,7 @@ class TestsFBX_AllPlatforms(object):
asset_processor, project, blackbox_param)
@pytest.mark.BAT
+ @pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests)
def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self,
workspace, ap_setup_fixture,
diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_ShaderBuildPipelineSuite.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_ShaderBuildPipelineSuite.py
deleted file mode 100644
index 9ef93ea238..0000000000
--- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_ShaderBuildPipelineSuite.py
+++ /dev/null
@@ -1,19 +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
-
-Main suite tests for the Shader Build Pipeline.
-"""
-import pytest
-from ly_test_tools import LAUNCHERS
-from ly_test_tools.o3de.editor_test import EditorTestSuite, EditorSingleTest
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestShaderBuildPipelineMain(EditorTestSuite):
- """Holds tests for Shader Build Pipeline validation"""
-
- class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSingleTest):
- from .atom_hydra_scripts import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
index b3030e84ac..f1299ddc2d 100644
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
@@ -14,8 +14,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
NAME AutomatedTesting::DynamicVegetationTests_Main
TEST_SERIAL
TEST_SUITE main
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
+ PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Main.py
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
@@ -27,104 +26,33 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationTests_Sandbox
+ NAME AutomatedTesting::DynamicVegetationTests_Periodic
TEST_SERIAL
- TEST_SUITE sandbox
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_sandbox"
+ TEST_SUITE periodic
+ PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Periodic.py
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
+ AutomatedTesting.Assets
AutomatedTesting.GameLauncher
- AutomatedTesting.Assets
COMPONENT
LargeWorlds
)
ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationFilterTests_Periodic
+ NAME AutomatedTesting::DynamicVegetationTests_Main_Optimized
TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_periodic and dynveg_filter"
+ TEST_SUITE main
+ PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Main_Optimized.py
RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
+ AZ::AssetProcessor
+ Legacy::Editor
+ AutomatedTesting.Assets
+ AutomatedTesting.GameLauncher
COMPONENT
LargeWorlds
)
- ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationModifierTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_periodic and dynveg_modifier"
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
- ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationRegressionTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_periodic and dynveg_regression"
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
- ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationAreaTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_periodic and dynveg_area"
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
- ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationMiscTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_periodic and dynveg_misc"
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
- ly_add_pytest(
- NAME AutomatedTesting::DynamicVegetationSurfaceTagTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg
- PYTEST_MARKS "SUITE_periodic and dynveg_surfacetagemitter"
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
## LandscapeCanvas ##
ly_add_pytest(
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py
index 928d38ac5a..e404624c93 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py
@@ -5,119 +5,119 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C4814463 - Altitude Filter overrides function as expected
-C4847477 - Altitude Min/Max can be manually set
-"""
-import os
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ prefilter_instance_count = (
+ "Pre-filter instance counts are accurate",
+ "Unexpected number of pre-filter instances found"
+ )
+ postfilter_instance_count = (
+ "Post-filter instance counts are accurate",
+ "Unexpected number of post-filter instances found"
+ )
+ postfilter_overrides_instance_count = (
+ "Override instance counts are accurate",
+ "Unexpected number of override instances found"
+ )
-class TestAltitudeFilterComponentAndOverrides(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="AltitudeFilterComponentAndOverrides", args=["level"])
+def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude():
+ """
+ Summary:
+ A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
+ on Z. An Altitude Filter is added to the spawner entity, and Altitude Min/Max values are set. Instance counts
+ are validated. The same test is then performed for Altitude Filter overrides.
- def run_test(self):
- """
- Summary:
- A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
- on Z. An Altitude Filter is added to the spawner entity, and Altitude Min/Max values are set. Instance counts
- are validated. The same test is then performed for Altitude Filter overrides.
+ Expected Behavior:
+ Instances are only spawned within the specified altitude ranges.
- Expected Behavior:
- Instances are only spawned within the specified altitude ranges.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create an instance spawner entity
+ 3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
+ 4) Initial instance counts pre-filter are verified.
+ 5) Altitude Min/Max is set on the Vegetation Altitude Filter component.
+ 6) Instance counts post-filter are verified.
+ 7) Altitude Min/Max is set on descriptor overrides.
+ 8) Instance counts post-filter are verified.
- Test Steps:
- 1) Create a new level
- 2) Create an instance spawner entity
- 3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
- 4) Initial instance counts pre-filter are verified.
- 5) Altitude Min/Max is set on the Vegetation Altitude Filter component.
- 6) Instance counts post-filter are verified.
- 7) Altitude Min/Max is set on descriptor overrides.
- 8) Instance counts post-filter are verified.
+ 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
- # 1) Create a new, temporary 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 azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Add a Vegetation Altitude Filter
- spawner_entity.add_component("Vegetation Altitude Filter")
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 3) Add surfaces to plant on
- dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
- elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
- dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
+ # 2) Create a new entity with required vegetation area components
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
- # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ # Add a Vegetation Altitude Filter
+ spawner_entity.add_component("Vegetation Altitude Filter")
- # 4) Verify initial instance counts pre-filter
- num_expected = (40 * 40) * 2 # 20 instances per 16m per side x 2 surfaces
- spawner_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and spawner_success
+ # 3) Add surfaces to plant on
+ dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
+ elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
+ dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
- # 5) Set min/max vegetation altitude, instances should now only appear between 35-37m on the Z-axis
- spawner_entity.get_set_test(3, "Configuration|Altitude Min", 35)
- spawner_entity.get_set_test(3, "Configuration|Altitude Max", 37)
+ # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- # 6) Validate expected instance counts
- num_expected = 40 * 40 # Instances should now only plant on the elevated surface
- altitude_min_max_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and altitude_min_max_success
+ # 4) Verify initial instance counts pre-filter
+ num_expected = (40 * 40) * 2 # 20 instances per 16m per side x 2 surfaces
+ spawner_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.prefilter_instance_count, spawner_success)
- # Resize Spawner Entity's Box Shape component to allow monitoring for a different instance count
- box_size = math.Vector3(16.0, 16.0, 16.0)
- spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", box_size)
+ # 5) Set min/max vegetation altitude, instances should now only appear between 35-37m on the Z-axis
+ spawner_entity.get_set_test(3, "Configuration|Altitude Min", 35)
+ spawner_entity.get_set_test(3, "Configuration|Altitude Max", 37)
- # 7) Allow overrides on Altitude Filter and set Altitude Filter Min/Max overrides on descriptor
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Override Enabled", True)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Min", 35)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Max", 37)
+ # 6) Validate expected instance counts
+ num_expected = 40 * 40 # Instances should now only plant on the elevated surface
+ altitude_min_max_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.postfilter_instance_count, altitude_min_max_success)
- # 8) Validate expected instances at specified elevations
- num_expected = 20 * 20 # 20 instances per 16m per side
- overrides_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and overrides_success
+ # Resize Spawner Entity's Box Shape component to allow monitoring for a different instance count
+ box_size = math.Vector3(16.0, 16.0, 16.0)
+ spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", box_size)
+
+ # 7) Allow overrides on Altitude Filter and set Altitude Filter Min/Max overrides on descriptor
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Override Enabled", True)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Min", 35)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Altitude Filter|Max", 37)
+
+ # 8) Validate expected instances at specified elevations
+ num_expected = 20 * 20 # 20 instances per 16m per side
+ overrides_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.postfilter_overrides_instance_count, overrides_success)
-test = TestAltitudeFilterComponentAndOverrides()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py
index 2ef72f72eb..3fc6a0afde 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py
@@ -5,90 +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
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ preprocess_instance_count = (
+ "Pre-process instance counts are accurate",
+ "Unexpected number of pre-process instances found"
+ )
+ postprocess_instance_count = (
+ "Post-process instance counts are accurate",
+ "Unexpected number of post-process instances found"
+ )
-class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="AltitudeFilter_FilterStageToggle", args=["level"])
+def AltitudeFilter_FilterStageToggle():
+ """
+ Summary:
+ Filter Stage toggle affects final vegetation position
- def run_test(self):
- """
- Summary:
- Filter Stage toggle affects final vegetation position
+ Expected Result:
+ Vegetation instances plant differently depending on the Filter Stage setting.
+ PostProcess should cause some number of plants that appear above and below the desired altitude range to disappear.
- Expected Result:
- Vegetation instances plant differently depending on the Filter Stage setting.
- PostProcess should cause some number of plants that appear above and below the desired altitude range to disappear.
+ :return: None
+ """
- :return: None
- """
+ import os
- PREPROCESS_INSTANCE_COUNT = 44
- POSTPROCESS_INSTANCE_COUNT = 34
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # 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,
- )
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- general.set_current_view_position(512.0, 480.0, 38.0)
+ PREPROCESS_INSTANCE_COUNT = 44
+ POSTPROCESS_INSTANCE_COUNT = 34
- # Create basic vegetation entity
- position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Add a Vegetation Altitude Filter to the vegetation area entity
- vegetation.add_component("Vegetation Altitude Filter")
+ # Create basic vegetation entity
+ position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
- # Create Surface for instances to plant on
- dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
+ # Add a Vegetation Altitude Filter to the vegetation area entity
+ vegetation.add_component("Vegetation Altitude Filter")
- # Add entity with Mesh to replicate creation of hills
- hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 10.0)
+ # Create Surface for instances to plant on
+ dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
- # Set a Min Altitude of 38 and Max of 40 in Vegetation Altitude Filter
- vegetation.get_set_test(3, "Configuration|Altitude Min", 38.0)
- vegetation.get_set_test(3, "Configuration|Altitude Max", 40.0)
+ # Add entity with Mesh to replicate creation of hills
+ hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 10.0)
- # Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient
- # Transform Modifier, and Box Shape component
- random_noise = hydra.Entity("random_noise")
- random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
- random_noise.set_test_parent_entity(vegetation)
+ # Set a Min Altitude of 38 and Max of 40 in Vegetation Altitude Filter
+ vegetation.get_set_test(3, "Configuration|Altitude Min", 38.0)
+ vegetation.get_set_test(3, "Configuration|Altitude Max", 40.0)
- # Add a Vegetation Position Modifier to the vegetation area entity.
- vegetation.add_component("Vegetation Position Modifier")
+ # Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient
+ # Transform Modifier, and Box Shape component
+ random_noise = hydra.Entity("random_noise")
+ random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
+ random_noise.set_test_parent_entity(vegetation)
- # Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
- vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
+ # Add a Vegetation Position Modifier to the vegetation area entity.
+ vegetation.add_component("Vegetation Position Modifier")
- # Toggle between PreProcess and PostProcess in Vegetation Altitude Filter
- vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, PREPROCESS_INSTANCE_COUNT), 2.0)
- self.log(f"Vegetation instances count equal to expected value for PREPROCESS filter stage: {result}")
- vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, POSTPROCESS_INSTANCE_COUNT), 2.0)
- self.log(f"Vegetation instances count equal to expected value for POSTPROCESS filter stage: {result}")
+ # Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
+ vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
+
+ # Toggle between PreProcess and PostProcess in Vegetation Altitude Filter
+ vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, PREPROCESS_INSTANCE_COUNT), 2.0)
+ Report.result(Tests.preprocess_instance_count, result)
+ vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 30.0, POSTPROCESS_INSTANCE_COUNT), 2.0)
+ Report.result(Tests.postprocess_instance_count, result)
-test = TestAltitudeFilterFilterStageToggle()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AltitudeFilter_FilterStageToggle)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py
index 8139ec5cac..bcd42b7fbb 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py
@@ -5,104 +5,105 @@ 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.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ prefilter_instance_count = (
+ "Pre-filter instance counts are accurate",
+ "Unexpected number of pre-filter instances found"
+ )
+ postfilter_instance_count = (
+ "Post-filter instance counts are accurate",
+ "Unexpected number of post-filter instances found"
+ )
-class TestAltitudeFilterShapeSample(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="AltitudeFilterShapeSample", args=["level"])
+def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude():
+ """
+ Summary:
+ A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
+ on Z. An Altitude Filter is added to the spawner entity, and set to sample a shape entity. Instance counts are
+ validated.
- def run_test(self):
- """
- Summary:
- A new level is created. A spawner entity is added, along with a planting surface at 32 on Z, and another at 36
- on Z. An Altitude Filter is added to the spawner entity, and set to sample a shape entity. Instance counts are
- validated.
+ Expected Behavior:
+ Instances are only spawned within the altitude range specified by the sampled shape.
- Expected Behavior:
- Instances are only spawned within the altitude range specified by the sampled shape.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create an instance spawner entity
+ 3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
+ 4) Initial instance counts pre-filter are verified.
+ 5) A new entity with shape is created, an sampled on the Vegetation Altitude Filter.
+ 6) Instance counts post-filter are verified.
- Test Steps:
- 1) Create a new level
- 2) Create an instance spawner entity
- 3) Create surfaces to plant on, one at 32 on Z and another at 36 on Z.
- 4) Initial instance counts pre-filter are verified.
- 5) A new entity with shape is created, an sampled on the Vegetation Altitude Filter.
- 6) Instance counts post-filter are verified.
+ 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
- # 1) Create a new, temporary 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 azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, asset_path)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Add a Vegetation Altitude Filter
- spawner_entity.add_component("Vegetation Altitude Filter")
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 3) Add surfaces to plant on
- dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
- elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
- dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
+ # 2) Create a new entity with required vegetation area components
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, asset_path)
- # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ # Add a Vegetation Altitude Filter
+ spawner_entity.add_component("Vegetation Altitude Filter")
- # 4) Verify initial instance counts pre-filter
- num_expected = (20 * 20) * 2 # 20 instances per 16m per side x 2 surfaces
- spawner_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and spawner_success
+ # 3) Add surfaces to plant on
+ dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
+ elevated_surface_center_point = math.Vector3(512.0, 512.0, 36.0)
+ dynveg.create_surface_entity("Planting Surface Elevated", elevated_surface_center_point, 32.0, 32.0, 1.0)
- # 5) Create a new entity with a shape at 36 on the Z-axis, and pin the entity to the Vegetation Altitude Filter
- shape_sampler_center_point = math.Vector3(512.0, 512.0, 36.0)
- shape_sampler = hydra.Entity("Shape Sampler")
- shape_sampler.create_entity(
- shape_sampler_center_point,
- ["Box Shape"]
- )
- if shape_sampler.id.IsValid():
- print(f"'{shape_sampler.name}' created")
- spawner_entity.get_set_test(3, 'Configuration|Pin To Shape Entity Id', shape_sampler.id)
+ # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- # 6) Validate expected instance counts
- num_expected = 20 * 20 # Instances should now only plant on the elevated surface
- sampler_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and sampler_success
+ # 4) Verify initial instance counts pre-filter
+ num_expected = (20 * 20) * 2 # 20 instances per 16m per side x 2 surfaces
+ spawner_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.prefilter_instance_count, spawner_success)
+
+ # 5) Create a new entity with a shape at 36 on the Z-axis, and pin the entity to the Vegetation Altitude Filter
+ shape_sampler_center_point = math.Vector3(512.0, 512.0, 36.0)
+ shape_sampler = hydra.Entity("Shape Sampler")
+ shape_sampler.create_entity(
+ shape_sampler_center_point,
+ ["Box Shape"]
+ )
+ if shape_sampler.id.IsValid():
+ print(f"'{shape_sampler.name}' created")
+ spawner_entity.get_set_test(3, 'Configuration|Pin To Shape Entity Id', shape_sampler.id)
+
+ # 6) Validate expected instance counts
+ num_expected = 20 * 20 # Instances should now only plant on the elevated surface
+ sampler_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.postfilter_instance_count, sampler_success)
-test = TestAltitudeFilterShapeSample()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AreaComponentSlices_SliceCreationAndVisibilityToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AreaComponentSlices_SliceCreationAndVisibilityToggle.py
deleted file mode 100755
index 095024cca1..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AreaComponentSlices_SliceCreationAndVisibilityToggle.py
+++ /dev/null
@@ -1,125 +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.legacy.general as general
-import azlmbr.slice as slice
-import azlmbr.bus as bus
-import azlmbr.editor as editor
-import azlmbr.asset as asset
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
-
-
-class TestAreaComponentsSliceCreationAndVisibilityToggle(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(
- self, log_prefix="AreaComponentSlices_SliceCreationAndVisibilityToggle", args=["level"]
- )
-
- def run_test(self):
- """
- Summary:
- C2627900 Verifies if a slice containing the component can be created.
- C2627905 A slice containing the Vegetation Layer Blender component can be created.
- C2627904: Hiding a slice containing the component clears any visuals from the Viewport.
-
- Expected Result:
- C2627900, C2627905: Slice is created, and is properly processed in the Asset Processor.
- C2627904: Vegetation area visuals are hidden from the Viewport.
-
- :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")
-
- # 1) 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,
- )
-
- general.set_current_view_position(512.0, 480.0, 38.0)
-
- # 2) C2627900 Verifies if a slice containing the Vegetation Layer Spawner component can be created.
- # 2.1) Create basic vegetation entity
- position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- veg_1 = dynveg.create_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path)
-
- # 2.2) Create slice from the entity
- slice_path = os.path.join("slices", "TestSlice_1.slice")
- slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", veg_1.id, slice_path)
-
- # 2.3) Verify if the slice has been created successfully
- self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
- self.log(
- f"Slice has been created successfully (entity with spawner component): {path_is_valid_asset(slice_path)}"
- )
-
- # 3) C2627904: Hiding a slice containing the component clears any visuals from the Viewport
- # 3.1) Create Surface for instances to plant on
- dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
-
- # 3.2) Initially verify instance count before hiding slice
- self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400))
- self.log(
- f"Vegetation plants initially when slice is shown: {dynveg.validate_instance_count(position, 16.0, 400)}"
- )
-
- # 3.3) Hide the slice and verify instance count
- editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, False)
- self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0))
- self.log(f"Vegetation is cleared when slice is hidden: {dynveg.validate_instance_count(position, 16.0, 0)}")
-
- # 3.4) Unhide the slice
- editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, True)
-
- # 4) C2627905 A slice containing the Vegetation Layer Blender component can be created.
- # 4.1) Create another vegetation entity to add to blender component
- veg_2 = dynveg.create_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "")
-
- # 4.2) Create entity with Vegetation Layer Blender
- components_to_add = ["Box Shape", "Vegetation Layer Blender"]
- blender_entity = hydra.Entity("blender_entity")
- blender_entity.create_entity(position, components_to_add)
-
- # 4.3) Pin both the vegetation areas to the blender entity
- pte = hydra.get_property_tree(blender_entity.components[1])
- path = "Configuration|Vegetation Areas"
- pte.update_container_item(path, 0, veg_1.id)
- pte.add_container_item(path, 1, veg_2.id)
-
- # 4.4) Drag the simple vegetation areas under the Vegetation Layer Blender entity to create an entity hierarchy.
- veg_1.set_test_parent_entity(blender_entity)
- veg_2.set_test_parent_entity(blender_entity)
-
- # 4.5) Create slice from blender entity
- slice_path = os.path.join("slices", "TestSlice_2.slice")
- slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", blender_entity.id, slice_path)
-
- # 4.6) Verify if the slice has been created successfully
- self.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
- self.log(
- f"Slice has been created successfully (entity with blender component): {path_is_valid_asset(slice_path)}"
- )
-
-
-test = TestAreaComponentsSliceCreationAndVisibilityToggle()
-test.run()
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py
index 5242160b35..7f6ce87110 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py
@@ -5,162 +5,167 @@ 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.legacy.general as general
-import azlmbr.math as math
-import azlmbr.paths
-import azlmbr.vegetation as vegetation
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ combined_instance_count_validation = (
+ "Combined instance counts are as expected",
+ "Found an unexpected number of instances"
+ )
+ replaced_asset_list_combined_instance_count_validation = (
+ "Combined instance counts are as expected after replacing an Asset List reference",
+ "Found an unexpected number of instances after replacing an Asset List reference"
+ )
+ removed_asset_lists_combined_instance_count_validation = (
+ "Instance counts are as expected after removing the referenced Asset Lists",
+ "Found an unexpected number of instances after removing the referenced Asset Lists"
+ )
-class TestAssetListCombiner(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="AssetListCombiner_CombinedDescriptors", args=["level"])
+def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea():
+ """
+ Summary:
+ Combined descriptors appear as expected in a vegetation area. Also verifies remove/replace of assigned Asset
+ Lists.
- def run_test(self):
- """
- Summary:
- Combined descriptors appear as expected in a vegetation area. Also verifies remove/replace of assigned Asset
- Lists.
+ Expected Behavior:
+ Vegetation fills in the area using the assets assigned to both Vegetation Asset Lists.
- Expected Behavior:
- Vegetation fills in the area using the assets assigned to both Vegetation Asset Lists.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
+ 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
+ on center instead of corner
+ 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
+ spawning empty assets
+ 5) Add 2 of the Asset List entities to the Vegetation Asset List Combiner component (PinkFlower and Empty)
+ 6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
+ as a child of the Constant Gradient entity, and configure for a checkerboard pattern
+ 7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
+ 8) Validate instance count with configured Asset List Combiner
+ 9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
+ instance count
+ 10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
+ Combiner component to force a refresh, and validate instance count
- Test Steps:
- 1) Create a new, temporary level
- 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
- 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
- on center instead of corner
- 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
- spawning empty assets
- 5) Add 2 of the Asset List entities to the Vegetation Asset List Combiner component (PinkFlower and Empty)
- 6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
- as a child of the Constant Gradient entity, and configure for a checkerboard pattern
- 7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
- 8) Validate instance count with configured Asset List Combiner
- 9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
- instance count
- 10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
- Combiner component to force a refresh, and validate instance count
+ 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
- def create_asset_list_entity(name, center, dynamic_slice_asset_path):
- asset_list_entity = hydra.Entity(name)
- asset_list_entity.create_entity(
- center,
- ["Vegetation Asset List"]
- )
- if asset_list_entity.id.IsValid():
- print(f"'{asset_list_entity.name}' created")
+ import azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+ import azlmbr.vegetation as vegetation
- # Set the Asset List to a Dynamic Slice spawner with a specific slice asset selected
- dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
- dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
- descriptor = hydra.get_component_property_value(asset_list_entity.components[0],
- "Configuration|Embedded Assets|[0]")
- descriptor.spawner = dynamic_slice_spawner
- asset_list_entity.get_set_test(0, "Configuration|Embedded Assets|[0]", descriptor)
- return asset_list_entity
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 1) Create a new, temporary 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 create_asset_list_entity(name, center, dynamic_slice_asset_path):
+ asset_list_entity = hydra.Entity(name)
+ asset_list_entity.create_entity(
+ center,
+ ["Vegetation Asset List"]
)
+ if asset_list_entity.id.IsValid():
+ print(f"'{asset_list_entity.name}' created")
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ # Set the Asset List to a Dynamic Slice spawner with a specific slice asset selected
+ dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
+ dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
+ descriptor = hydra.get_component_property_value(asset_list_entity.components[0],
+ "Configuration|Embedded Assets|[0]")
+ descriptor.spawner = dynamic_slice_spawner
+ asset_list_entity.get_set_test(0, "Configuration|Embedded Assets|[0]", descriptor)
+ return asset_list_entity
- # 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- asset_path2 = os.path.join("Slices", "PurpleFlower.dynamicslice")
- asset_list_entity = create_asset_list_entity("Asset List 1", center_point, asset_path)
- asset_list_entity2 = create_asset_list_entity("Asset List 2", center_point, None)
- asset_list_entity3 = create_asset_list_entity("Asset List 3", center_point, asset_path2)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
- # on center instead of corner
- dynveg.create_surface_entity("Surface Entity", center_point, 32.0, 32.0, 1.0)
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
- # spawning empty assets
- spawner_entity = dynveg.create_vegetation_area("Spawner Entity", center_point, 16.0, 16.0, 16.0, None)
- spawner_entity.remove_component("Vegetation Asset List")
- spawner_entity.add_component("Vegetation Asset List Combiner")
- spawner_entity.add_component("Vegetation Asset Weight Selector")
- spawner_entity.get_set_test(0, "Configuration|Allow Empty Assets", False)
+ # 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ asset_path2 = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ asset_list_entity = create_asset_list_entity("Asset List 1", center_point, asset_path)
+ asset_list_entity2 = create_asset_list_entity("Asset List 2", center_point, None)
+ asset_list_entity3 = create_asset_list_entity("Asset List 3", center_point, asset_path2)
- # 5) Add the Asset List entities to the Vegetation Asset List Combiner component
- asset_list_entities = [asset_list_entity.id, asset_list_entity2.id]
- spawner_entity.get_set_test(2, "Configuration|Descriptor Providers", asset_list_entities)
+ # 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn
+ # on center instead of corner
+ dynveg.create_surface_entity("Surface Entity", center_point, 32.0, 32.0, 1.0)
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- # 6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
- # as a child of the Constant Gradient entity, and configure for a checkerboard pattern
- components_to_add = ["Constant Gradient"]
- constant_gradient_entity = hydra.Entity("Constant Gradient Entity")
- constant_gradient_entity.create_entity(center_point, components_to_add, parent_id=spawner_entity.id)
- constant_gradient_entity.get_set_test(0, "Configuration|Value", 0.5)
+ # 4) Create a spawner using a Vegetation Asset List Combiner component and a Weight Selector, and disallow
+ # spawning empty assets
+ spawner_entity = dynveg.create_vegetation_area("Spawner Entity", center_point, 16.0, 16.0, 16.0, None)
+ spawner_entity.remove_component("Vegetation Asset List")
+ spawner_entity.add_component("Vegetation Asset List Combiner")
+ spawner_entity.add_component("Vegetation Asset Weight Selector")
+ spawner_entity.get_set_test(0, "Configuration|Allow Empty Assets", False)
- components_to_add = ["Dither Gradient Modifier"]
- dither_gradient_entity = hydra.Entity("Dither Gradient Entity")
- dither_gradient_entity.create_entity(center_point, components_to_add, parent_id=constant_gradient_entity.id)
- dither_gradient_entity.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", constant_gradient_entity.id)
+ # 5) Add the Asset List entities to the Vegetation Asset List Combiner component
+ asset_list_entities = [asset_list_entity.id, asset_list_entity2.id]
+ spawner_entity.get_set_test(2, "Configuration|Descriptor Providers", asset_list_entities)
- # 7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
- spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", dither_gradient_entity.id)
+ # 6) Create a Constant Gradient entity as a child of the spawner entity, and a Dither Gradient Modifier entity
+ # as a child of the Constant Gradient entity, and configure for a checkerboard pattern
+ components_to_add = ["Constant Gradient"]
+ constant_gradient_entity = hydra.Entity("Constant Gradient Entity")
+ constant_gradient_entity.create_entity(center_point, components_to_add, parent_id=spawner_entity.id)
+ constant_gradient_entity.get_set_test(0, "Configuration|Value", 0.5)
- # 8) Validate instance count. We should now have 200 instances in the spawner area as every other instance
- # should be an empty asset which the spawner is set to disallow
- num_expected = 20 * 20 / 2
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ components_to_add = ["Dither Gradient Modifier"]
+ dither_gradient_entity = hydra.Entity("Dither Gradient Entity")
+ dither_gradient_entity.create_entity(center_point, components_to_add, parent_id=constant_gradient_entity.id)
+ dither_gradient_entity.get_set_test(0, "Configuration|Gradient|Gradient Entity Id", constant_gradient_entity.id)
- # 9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
- # instance count. Should now be 400 instances as the empty spaces can now be claimed by the new descriptor
- spawner_entity.get_set_test(2, "Configuration|Descriptor Providers|[1]", asset_list_entity3.id)
- num_expected = 20 * 20
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ # 7) Pin the Dither Gradient Entity to the Asset Weight Selector of the spawner entity
+ spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", dither_gradient_entity.id)
- # 10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
- # Combiner component to force a refresh, and validate instance count. We should now have 0 instances.
- pte = hydra.get_property_tree(spawner_entity.components[2])
- path = "Configuration|Descriptor Providers"
- pte.reset_container(path)
- # Component refresh is currently necessary due to container operations not causing a refresh (LY-120947)
- editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [spawner_entity.components[2]])
- editor.EditorComponentAPIBus(bus.Broadcast, "EnableComponents", [spawner_entity.components[2]])
- num_expected = 0
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ # 8) Validate instance count. We should now have 200 instances in the spawner area as every other instance
+ # should be an empty asset which the spawner is set to disallow
+ num_expected = 20 * 20 / 2
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.combined_instance_count_validation, success)
+
+ # 9) Replace the reference to the 2nd asset list on the Vegetation Asset List Combiner component and validate
+ # instance count. Should now be 400 instances as the empty spaces can now be claimed by the new descriptor
+ spawner_entity.get_set_test(2, "Configuration|Descriptor Providers|[1]", asset_list_entity3.id)
+ num_expected = 20 * 20
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.replaced_asset_list_combined_instance_count_validation, success)
+
+ # 10) Remove the referenced Asset Lists on the Asset List Combiner, Disable/Re-enable the Asset List
+ # Combiner component to force a refresh, and validate instance count. We should now have 0 instances.
+ pte = hydra.get_property_tree(spawner_entity.components[2])
+ path = "Configuration|Descriptor Providers"
+ pte.reset_container(path)
+ # Component refresh is currently necessary due to container operations not causing a refresh (LY-120947)
+ editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [spawner_entity.components[2]])
+ editor.EditorComponentAPIBus(bus.Broadcast, "EnableComponents", [spawner_entity.components[2]])
+ num_expected = 0
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.removed_asset_lists_combined_instance_count_validation, success)
-test = TestAssetListCombiner()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py
index 113bbc8ea8..53b45e8470 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py
@@ -5,112 +5,110 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C6269654: Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
-"""
-import os
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ highest_weight_instance_count = (
+ "Found the expected number of instances when sorting by highest weight",
+ "Found an unexpected number of instances when sorting by highest weight"
+ )
+ lowest_weight_instance_count = (
+ "Found the expected number of instances when sorting by lowest weight",
+ "Found an unexpected number of instances when sorting by lowest weight"
+ )
-class TestAssetWeightSelectorSortByWeight(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="AssetWeightSelector_SortByWeight", args=["level"])
+def AssetWeightSelector_InstancesExpressBasedOnWeight():
+ """
+ Summary:
+ Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
- def run_test(self):
- """
- Summary:
- Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
+ Expected Behavior:
+ Vegetation is planted in the area according to the generated gradient pattern.
+ Higher weight assets are more likely to express when "Descending (highest first)" is selected.
+ Lower weight assets are more likely to express when "Ascending (lowest first)" is selected.
- Expected Behavior:
- Vegetation is planted in the area according to the generated gradient pattern.
- Higher weight assets are more likely to express when "Descending (highest first)" is selected.
- Lower weight assets are more likely to express when "Ascending (lowest first)" is selected.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create instance spawner with 2 descriptors, one with an Empty Asset
+ 3) Create a planting surface
+ 4) Create a child entity of the instance spawner with a Constant Gradient component with default values (1.0)
+ 5) Pin the child entity to Vegetation Asset Weight Selector of the instance spawner entity
+ 6) Set first descriptor to a higher weight, and toggle off Allow Empty Assets
+ 7) Validate instance count with initial setup/sort values
+ 8) Change sort values and validate instance count
- Test Steps:
- 1) Create new level
- 2) Create instance spawner with 2 descriptors, one with an Empty Asset
- 3) Create a planting surface
- 4) Create a child entity of the instance spawner with a Constant Gradient component with default values (1.0)
- 5) Pin the child entity to Vegetation Asset Weight Selector of the instance spawner entity
- 6) Set first descriptor to a higher weight, and toggle off Allow Empty Assets
- 7) Validate instance count with initial setup/sort values
- 8) Change sort values and validate instance count
+ 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 a new, temporary 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
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors, one set to a
- # valid slice entity, and one set to None
- spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
- asset_path)
- desc_asset = hydra.get_component_property_value(spawner_entity.components[2],
- "Configuration|Embedded Assets")[0]
- desc_list = [desc_asset, desc_asset]
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[1]|Instance|Slice Asset", None)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Add an Asset Weight Selector component to the spawner entity
- spawner_entity.add_component("Vegetation Asset Weight Selector")
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Create a planting surface
- dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 1.0)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 4) Create a child entity of the spawner entity with a Constant Gradient component
- components_to_add = ["Constant Gradient"]
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
+ # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors, one set to a
+ # valid slice entity, and one set to None
+ spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+ asset_path)
+ desc_asset = hydra.get_component_property_value(spawner_entity.components[2],
+ "Configuration|Embedded Assets")[0]
+ desc_list = [desc_asset, desc_asset]
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[1]|Instance|Slice Asset", None)
- # 5) Pin the Constant Gradient to the Vegetation Asset Weight Selector
- spawner_entity.get_set_test(3, 'Configuration|Gradient|Gradient Entity Id', gradient_entity.id)
+ # Add an Asset Weight Selector component to the spawner entity
+ spawner_entity.add_component("Vegetation Asset Weight Selector")
- # 6) Set the first descriptor weight to a higher value and toggle off Allow Empty Assets on the Layer Spawner
- # component
- spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Weight', 50)
- spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
+ # 3) Create a planting surface
+ dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 1.0)
- # 7) Query for expected instances with default settings. We should have 0 instances with default Constant
- # Gradient setup sorting by higher weight first
- num_expected = 0
- initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = initial_success and self.test_success
+ # 4) Create a child entity of the spawner entity with a Constant Gradient component
+ components_to_add = ["Constant Gradient"]
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
- # 8) Sort by lowest weight first, and verify instance counts. We should now have 400 instances as the highest
- # priority instance won't be allowed to claim space due to "Allow Empty Assets" being False
- spawner_entity.get_set_test(3, 'Configuration|Sort By Weight', 1)
- num_expected = 20 * 20
- final_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = final_success and self.test_success
+ # 5) Pin the Constant Gradient to the Vegetation Asset Weight Selector
+ spawner_entity.get_set_test(3, 'Configuration|Gradient|Gradient Entity Id', gradient_entity.id)
+
+ # 6) Set the first descriptor weight to a higher value and toggle off Allow Empty Assets on the Layer Spawner
+ # component
+ spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Weight', 50)
+ spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
+
+ # 7) Query for expected instances with default settings. We should have 0 instances with default Constant
+ # Gradient setup sorting by higher weight first
+ num_expected = 0
+ initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.highest_weight_instance_count, initial_success)
+
+ # 8) Sort by lowest weight first, and verify instance counts. We should now have 400 instances as the highest
+ # priority instance won't be allowed to claim space due to "Allow Empty Assets" being False
+ spawner_entity.get_set_test(3, 'Configuration|Sort By Weight', 1)
+ num_expected = 20 * 20
+ final_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.lowest_weight_instance_count, final_success)
-test = TestAssetWeightSelectorSortByWeight()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AssetWeightSelector_InstancesExpressBasedOnWeight)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py
index 12fb6d8eff..c2adffc6ca 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py
@@ -5,108 +5,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
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_instance_counts = (
+ "Initial instance counts are as expected",
+ "Unexpected number of initial instances found"
+ )
+ instance_counts_1m = (
+ "Instance counts with 1 meters between instances are as expected",
+ "Unexpected number of instances found with 1 meters between instances"
+ )
+ instance_counts_2m = (
+ "Instance counts with 2 meters between instances are as expected",
+ "Unexpected number of instances found with 2 meters between instances"
+ )
+ instance_counts_16m = (
+ "Instance counts with 16 meters between instances are as expected",
+ "Unexpected number of instances found with 16 meters between instances"
+ )
-class TestDistanceBetweenFilterComponentOverrides(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="DistanceBetweenFilterComponentOverrides", args=["level"])
+def DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius():
+ """
+ Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
+ added and the min radius is changed as an override on the descriptor. Instance counts at specific points are
+ validated.
- def run_test(self):
- """
- Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
- added and the min radius is changed as an override on the descriptor. Instance counts at specific points are
- validated.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create a vegetation area
+ 3) Create a surface for planting
+ 4) Add the Vegetation System Settings component and setup for the test
+ 5-8) Add the Distance Between Filter, setup overrides on both the component and descriptor, and validate
+ expected instance counts with a few different Radius values
- Test Steps:
- 1) Create a new level
- 2) Create a vegetation area
- 3) Create a surface for planting
- 4) Add the Vegetation System Settings component and setup for the test
- 5-8) Add the Distance Between Filter, setup overrides on both the component and descriptor, and validate
- expected instance counts with a few different Radius values
+ 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
- """
- instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
- instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
- instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
+ import os
- # 1) Create a new, temporary 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 azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- general.set_current_view_position(512.0, 480.0, 38.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components
- spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
- asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
- asset_path)
+ instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
+ instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
+ instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
- # 3) Create a surface to plant on
- surface_center_point = math.Vector3(512.0, 512.0, 32.0)
- dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Density', 16)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # 5) Add a Vegetation Distance Between Filter, toggle overrides on both the component and descriptor,
- # and verify initial instance counts are accurate
- spawner_entity.add_component("Vegetation Distance Between Filter")
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Override Enabled", True)
- num_expected = 16 * 16
- initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and initial_success
+ # 2) Create a new entity with required vegetation area components
+ spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
+ asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+ asset_path)
- # 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 1.0)
- point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
- point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
- point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
- self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
+ # 3) Create a surface to plant on
+ surface_center_point = math.Vector3(512.0, 512.0, 32.0)
+ dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
- # 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 2.0)
- point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
- point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
- point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
- self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
+ # 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Density', 16)
- # 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate, only a single instance should plant
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 16.0)
- num_expected_instances = 1
- final_check_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = self.test_success and final_check_success
+ # 5) Add a Vegetation Distance Between Filter, toggle overrides on both the component and descriptor,
+ # and verify initial instance counts are accurate
+ spawner_entity.add_component("Vegetation Distance Between Filter")
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Override Enabled", True)
+ num_expected = 16 * 16
+ initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.initial_instance_counts, initial_success)
+
+ # 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 1.0)
+ point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
+ point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
+ point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
+ Report.result(Tests.instance_counts_1m, point_a_success and point_b_success and point_c_success)
+
+ # 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 2.0)
+ point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
+ point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
+ point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
+ Report.result(Tests.instance_counts_2m, point_a_success and point_b_success and point_c_success)
+
+ # 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate, only a single instance should plant
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min", 16.0)
+ num_expected_instances = 1
+ final_check_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(Tests.instance_counts_16m, final_check_success)
-test = TestDistanceBetweenFilterComponentOverrides()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py
index 5b978c6212..de0d9a14fe 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py
@@ -5,104 +5,113 @@ 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.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_instance_counts = (
+ "Initial instance counts are as expected",
+ "Unexpected number of initial instances found"
+ )
+ instance_counts_1m = (
+ "Instance counts with 1 meters between instances are as expected",
+ "Unexpected number of instances found with 1 meters between instances"
+ )
+ instance_counts_2m = (
+ "Instance counts with 2 meters between instances are as expected",
+ "Unexpected number of instances found with 2 meters between instances"
+ )
+ instance_counts_16m = (
+ "Instance counts with 16 meters between instances are as expected",
+ "Unexpected number of instances found with 16 meters between instances"
+ )
-class TestDistanceBetweenFilterComponent(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="DistanceBetweenFilterComponent", args=["level"])
+def DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius():
+ """
+ Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
+ added and the min radius is changed. Instance counts at specific points are validated.
- def run_test(self):
- """
- Summary: Creates a level with a simple vegetation area. A Vegetation Distance Between Filter is
- added and the min radius is changed. Instance counts at specific points are validated.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create a vegetation area
+ 3) Create a surface for planting
+ 4) Add the Vegetation System Settings component and setup for the test
+ 5-8) Add the Distance Between Filter, and validate expected instance counts with a few different Radius values
- Test Steps:
- 1) Create a new level
- 2) Create a vegetation area
- 3) Create a surface for planting
- 4) Add the Vegetation System Settings component and setup for the test
- 5-8) Add the Distance Between Filter, and validate expected instance counts with a few different Radius values
+ 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
- """
- instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
- instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
- instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
+ import os
- # 1) Create a new, temporary 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 azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- general.set_current_view_position(512.0, 480.0, 38.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components
- spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
- asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
- asset_path)
+ instance_query_point_a = math.Vector3(512.5, 512.5, 32.0)
+ instance_query_point_b = math.Vector3(514.0, 512.5, 32.0)
+ instance_query_point_c = math.Vector3(515.0, 512.5, 32.0)
- # 3) Create a surface to plant on
- surface_center_point = math.Vector3(512.0, 512.0, 32.0)
- dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Density', 16)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # 5) Add a Vegetation Distance Between Filter and verify initial instance counts are accurate
- spawner_entity.add_component("Vegetation Distance Between Filter")
- num_expected = 16 * 16
- num_expected = 16 * 16
- initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and initial_success
+ # 2) Create a new entity with required vegetation area components
+ spawner_center_point = math.Vector3(520.0, 520.0, 32.0)
+ asset_path = os.path.join("Slices", "1m_cube.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+ asset_path)
- # 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
- spawner_entity.get_set_test(3, "Configuration|Radius Min", 1.0)
- point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
- point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
- point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
- self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
+ # 3) Create a surface to plant on
+ surface_center_point = math.Vector3(512.0, 512.0, 32.0)
+ dynveg.create_surface_entity("Planting Surface", surface_center_point, 128.0, 128.0, 1.0)
- # 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
- spawner_entity.get_set_test(3, "Configuration|Radius Min", 2.0)
- point_a_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
- point_b_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
- point_c_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
- self.test_success = self.test_success and point_a_success and point_b_success and point_c_success
+ # 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Density', 16)
- # 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate
- spawner_entity.get_set_test(3, "Configuration|Radius Min", 16.0)
- num_expected_instances = 1
- final_check_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = final_check_success and self.test_success
+ # 5) Add a Vegetation Distance Between Filter and verify initial instance counts are accurate
+ spawner_entity.add_component("Vegetation Distance Between Filter")
+ num_expected = 16 * 16
+ initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.initial_instance_counts, initial_success)
+
+ # 6) Change Radius Min to 1.0, refresh, and verify instance counts are accurate
+ spawner_entity.get_set_test(3, "Configuration|Radius Min", 1.0)
+ point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
+ point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
+ point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 1), 5.0)
+ Report.result(Tests.instance_counts_1m, point_a_success and point_b_success and point_c_success)
+
+ # 7) Change Radius Min to 2.0, refresh, and verify instance counts are accurate
+ spawner_entity.get_set_test(3, "Configuration|Radius Min", 2.0)
+ point_a_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_a, 0.5, 1), 5.0)
+ point_b_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_b, 0.5, 0), 5.0)
+ point_c_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(instance_query_point_c, 0.5, 0), 5.0)
+ Report.result(Tests.instance_counts_2m, point_a_success and point_b_success and point_c_success)
+
+ # 8) Change Radius Min to 16.0, refresh, and verify instance counts are accurate
+ spawner_entity.get_set_test(3, "Configuration|Radius Min", 16.0)
+ num_expected_instances = 1
+ final_check_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(Tests.instance_counts_16m, final_check_success)
-test = TestDistanceBetweenFilterComponent()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py
index 173be62829..fcbf85c59d 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py
@@ -5,140 +5,178 @@ 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.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class BehaviorContextTests:
+ spawner_initialized = (
+ "Successfully initialized a Dynamic Slice Instance Spawner",
+ "Failed to initialize a Dynamic Slice Instance Spawner"
+ )
+ spawner_slice_asset_path_set = (
+ "Successfully set a Dynamic Slice asset path",
+ "Failed to set a Dynamic Slice asset path"
+ )
+ spawner_empty_slice_asset_path_set = (
+ "Successfully set an empty Dynamic Slice asset path",
+ "Failed to set an empty Dynamic Slice asset path"
+ )
+ desc_spawnertype_sets_spawner = (
+ "Setting spawnerType sets spawner too",
+ "Setting spawnerType failed to set spawner to expected value"
+ )
+ desc_spawner_sets_spawnertype = (
+ "Setting spawner sets spawnerType too",
+ "Setting spawner failed to set spawnerType to expected value"
+ )
-class TestDynamicSliceInstanceSpawner(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawner", args=["level"])
+class PropertyTreeTests:
+ entity_created = (
+ "Spawner entity created successfully",
+ "Failed to create spawner entity"
+ )
+ spawner_type_set = (
+ "Successfully set spawner type",
+ "Failed to set spawner type"
+ )
+ empty_instance_count_validation = (
+ "Expected number of empty instances planted",
+ "Unexpected number of empty instances planted"
+ )
+ no_instances_when_empty_disallowed = (
+ "No empty instances found when Empty Assets are not allowed",
+ "Unexpectedly found empty instances when Empty Assets are not allowed"
+ )
+ nonempty_asset_instance_count_validation = (
+ "Expected number of instances planted",
+ "Unexpected number of instances planted"
+ )
- def run_test(self):
- """
- Summary:
- Test aspects of the DynamicSliceInstanceSpawner through the BehaviorContext and the Property Tree.
- :return: None
- """
- # 1) Open an 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 DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks():
+ """
+ Summary:
+ Test aspects of the DynamicSliceInstanceSpawner through the BehaviorContext and the Property Tree.
+
+ :return: None
+ """
+
+ import os
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+ general.set_current_view_position(512.0, 480.0, 38.0)
+
+ # Grab the UUID that we need for creating an Dynamic Slice Instance Spawner
+ dynamic_slice_spawner_uuid = azlmbr.math.Uuid_CreateString('{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}', 0)
+
+ # Grab a path to a test dynamic slice asset
+ test_slice_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+
+ # 2) Test DynamicSliceInstanceSpawner BehaviorContext
+ behavior_context_test_success = True
+ dynamic_slice_spawner = azlmbr.vegetation.DynamicSliceInstanceSpawner()
+ behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner is not None)
+ behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner.typename == 'DynamicSliceInstanceSpawner')
+ Report.critical_result(BehaviorContextTests.spawner_initialized, behavior_context_test_success)
+ # Try to get/set the slice asset path with a valid asset
+ dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
+ validate_path = dynamic_slice_spawner.GetSliceAssetPath()
+ # We expect the path to get lowercased and normalized with a forward slash, so we compare our result
+ # vs that instead of directly against test_slice_asset_path.
+ behavior_context_test_success = behavior_context_test_success and hydra.compare_values('slices/pinkflower.dynamicslice', validate_path, 'GetSliceAssetPath - valid')
+ Report.result(BehaviorContextTests.spawner_slice_asset_path_set, behavior_context_test_success)
+ # Try to get/set the slice asset path with an empty path
+ dynamic_slice_spawner.SetSliceAssetPath('')
+ validate_path = dynamic_slice_spawner.GetSliceAssetPath()
+ behavior_context_test_success = behavior_context_test_success and hydra.compare_values('', validate_path, 'GetSliceAssetPath - empty')
+ Report.result(BehaviorContextTests.spawner_empty_slice_asset_path_set, behavior_context_test_success)
+ Report.info(f'DynamicSliceInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
+
+ # 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
+ spawner_type_test_success = True
+ descriptor = azlmbr.vegetation.Descriptor()
+ spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', dynamic_slice_spawner_uuid)
+ spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
+ Report.result(BehaviorContextTests.desc_spawnertype_sets_spawner, spawner_type_test_success)
+ Report.info(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
+
+ # 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
+ spawner_test_success = True
+ descriptor = azlmbr.vegetation.Descriptor()
+ descriptor.spawner = dynamic_slice_spawner
+ spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(dynamic_slice_spawner_uuid))
+ spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
+ Report.result(BehaviorContextTests.desc_spawner_sets_spawnertype, spawner_test_success)
+ Report.info(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
+
+ ### Setup for Property Tree set of tests
+
+ # Create a new entity with required vegetation area components
+ spawner_entity = hydra.Entity("Veg Area")
+ spawner_entity.create_entity(
+ math.Vector3(512.0, 512.0, 32.0),
+ ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
)
- general.idle_wait(1.0)
- general.set_current_view_position(512.0, 480.0, 38.0)
+ Report.critical_result(PropertyTreeTests.entity_created, spawner_entity.id.IsValid())
- # Grab the UUID that we need for creating an Dynamic Slice Instance Spawner
- dynamic_slice_spawner_uuid = azlmbr.math.Uuid_CreateString('{BBA5CC1E-B4CA-4792-89F7-93711E98FBD1}', 0)
+ # Resize the Box Shape component
+ new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
+ box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
+ spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
- # Grab a path to a test dynamic slice asset
- test_slice_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ # Create a surface to plant on
+ dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
- # 2) Test DynamicSliceInstanceSpawner BehaviorContext
- behavior_context_test_success = True
- dynamic_slice_spawner = azlmbr.vegetation.DynamicSliceInstanceSpawner()
- behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner is not None)
- behavior_context_test_success = behavior_context_test_success and (dynamic_slice_spawner.typename == 'DynamicSliceInstanceSpawner')
- # Try to get/set the slice asset path with a valid asset
- dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
- validate_path = dynamic_slice_spawner.GetSliceAssetPath()
- # We expect the path to get lowercased and normalized with a forward slash, so we compare our result
- # vs that instead of directly against test_slice_asset_path.
- behavior_context_test_success = behavior_context_test_success and hydra.compare_values('slices/pinkflower.dynamicslice', validate_path, 'GetSliceAssetPath - valid')
- # Try to get/set the slice asset path with an empty path
- dynamic_slice_spawner.SetSliceAssetPath('')
- validate_path = dynamic_slice_spawner.GetSliceAssetPath()
- behavior_context_test_success = behavior_context_test_success and hydra.compare_values('', validate_path, 'GetSliceAssetPath - empty')
- self.test_success = self.test_success and behavior_context_test_success
- self.log(f'DynamicSliceInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
+ # 5) Descriptor Property Tree test: spawner type can be set
- # 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
- spawner_type_test_success = True
- descriptor = azlmbr.vegetation.Descriptor()
- spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', dynamic_slice_spawner_uuid)
- spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
- self.test_success = self.test_success and spawner_type_test_success
- self.log(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
+ # - Validate the dynamic slice spawner type can be set correctly.
+ property_tree_success = True
+ property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', dynamic_slice_spawner_uuid)
+ Report.result(PropertyTreeTests.spawner_type_set, property_tree_success)
- # 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
- spawner_test_success = True
- descriptor = azlmbr.vegetation.Descriptor()
- descriptor.spawner = dynamic_slice_spawner
- spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(dynamic_slice_spawner_uuid))
- spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'DynamicSliceInstanceSpawner')
- self.test_success = self.test_success and spawner_test_success
- self.log(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
+ # This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
+ # 20 instances per 16 meters
+ spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', True)
+ num_expected_instances = 20 * 20
+ property_tree_success = property_tree_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(PropertyTreeTests.empty_instance_count_validation, property_tree_success)
+ Report.info(f'Property Tree spawner type test: {property_tree_success}')
- ### Setup for Property Tree set of tests
+ # 6) Validate that the "Allow Empty Assets" setting affects the DynamicSliceInstanceSpawner
+ allow_empty_assets_success = True
+ # Since we have an empty slice path, we should have 0 instances once we disable 'Allow Empty Assets'
+ num_expected_instances = 0
+ allow_empty_assets_success = allow_empty_assets_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
+ Report.info('Allow Empty Assets test:')
+ allow_empty_assets_success = allow_empty_assets_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(PropertyTreeTests.no_instances_when_empty_disallowed, allow_empty_assets_success)
+ Report.info(f'Allow Empty Assets test: {allow_empty_assets_success}')
- # Create a new entity with required vegetation area components
- spawner_entity = hydra.Entity("Veg Area")
- spawner_entity.create_entity(
- math.Vector3(512.0, 512.0, 32.0),
- ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
- )
- if (spawner_entity.id.IsValid()):
- self.log(f"'{spawner_entity.name}' created")
-
- # Resize the Box Shape component
- new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
- box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
- spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
-
- # Create a surface to plant on
- dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
-
- # 5) Descriptor Property Tree test: spawner type can be set
-
- # - Validate the dynamic slice spawner type can be set correctly.
- property_tree_success = True
- property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', dynamic_slice_spawner_uuid)
-
- # This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
- # 20 instances per 16 meters
- spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', True)
- num_expected_instances = 20 * 20
- property_tree_success = property_tree_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = self.test_success and property_tree_success
- self.log(f'Property Tree spawner type test: {property_tree_success}')
-
- # 6) Validate that the "Allow Empty Assets" setting affects the DynamicSliceInstanceSpawner
- allow_empty_assets_success = True
- # Since we have an empty slice path, we should have 0 instances once we disable 'Allow Empty Assets'
- num_expected_instances = 0
- allow_empty_assets_success = allow_empty_assets_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
- self.log('Allow Empty Assets test:')
- allow_empty_assets_success = allow_empty_assets_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = self.test_success and allow_empty_assets_success
- self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
-
- # 7) Validate that with 'Allow Empty Assets' set to False, a non-empty slice asset gives us the number
- # of instances we expect.
- spawns_slices_success = True
- num_expected_instances = 20 * 20
- dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
- spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
- descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
- descriptor.spawner = dynamic_slice_spawner
- spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
- self.log('Spawn dynamic slices test:')
- spawns_slices_success = spawns_slices_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = self.test_success and spawns_slices_success
- self.log(f'Spawn dynamic slices test: {spawns_slices_success}')
+ # 7) Validate that with 'Allow Empty Assets' set to False, a non-empty slice asset gives us the number
+ # of instances we expect.
+ spawns_slices_success = True
+ num_expected_instances = 20 * 20
+ dynamic_slice_spawner.SetSliceAssetPath(test_slice_asset_path)
+ spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
+ descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
+ descriptor.spawner = dynamic_slice_spawner
+ spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
+ Report.info('Spawn dynamic slices test:')
+ spawns_slices_success = spawns_slices_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(PropertyTreeTests.nonempty_asset_instance_count_validation, spawns_slices_success)
+ Report.info(f'Spawn dynamic slices test: {spawns_slices_success}')
-test = TestDynamicSliceInstanceSpawner()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
index 6f2e711387..e51be58ec6 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
@@ -5,99 +5,115 @@ 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.components as components
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-import azlmbr.entity as entity
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ level_created = (
+ "Successfully created level",
+ "Failed to create level"
+ )
+ spawner_entity_created = (
+ "Spawner entity created successfully",
+ "Failed to create spawner entity"
+ )
+ surface_entity_created = (
+ "Surface entity created successfully",
+ "Failed to create surface entity"
+ )
+ instance_count = (
+ "Found the expected number of instances",
+ "Found an unexpected number of instances"
+ )
+ saved_and_exported = (
+ "Saved and exported level successfully",
+ "Failed to save and export level"
+ )
-class TestDynamicSliceInstanceSpawnerEmbeddedEditor(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawnerEmbeddedEditor", args=["level"])
+def DynamicSliceInstanceSpawner_Embedded_E2E():
+ """
+ Summary:
+ A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
+ Dynamic Slice Instance Spawner type.
- def run_test(self):
- """
- Summary:
- A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
- Dynamic Slice Instance Spawner type.
+ Expected Behavior:
+ Instances plant as expected in the assigned area.
- Expected Behavior:
- Instances plant as expected in the assigned area.
+ Test Steps:
+ 1) Create level
+ 2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
+ 3) Create a surface to plant on
+ 4) Verify expected instance counts
+ 5) Add a camera component looking at the planting area for visual debugging
+ 6) Save and export to engine
- Test Steps:
- 1) Create level
- 2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
- 3) Create a surface to plant on
- 4) Verify expected instance counts
- 5) Add a camera component looking at the planting area for visual debugging
- 6) Save and export to engine
+ 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
- # 1) Create a new, temporary 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 azlmbr.asset as asset
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.components as components
+ import azlmbr.entity as entity
+ import azlmbr.math as math
+ import azlmbr.paths as paths
- general.set_current_view_position(512.0, 480.0, 38.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path)
- spawner_entity.add_component("Script Canvas")
- instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
- instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
- math.Uuid(), False)
- spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
+ # 1) Create a new, temporary level
+ lvl_name = "tmp_level"
+ helper.init_idle()
+ level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
+ general.idle_wait(1.0)
+ Report.critical_result(Tests.level_created, level_created == 0)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # 3) Create a surface to plant on
- dynveg.create_surface_entity("Planting Surface", center_point, 128.0, 128.0, 1.0)
+ # 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path)
+ spawner_entity.add_component("Script Canvas")
+ instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
+ instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
+ math.Uuid(), False)
+ spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
+ Report.result(Tests.spawner_entity_created, spawner_entity.id.IsValid() and hydra.has_components(spawner_entity.id,
+ ["Script Canvas"]))
- # 4) Verify instance counts are accurate
- general.idle_wait(3.0) # Allow a few seconds for instances to spawn
- num_expected_instances = 20 * 20
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
- self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
- self.test_success = self.test_success and num_found == num_expected_instances
+ # 3) Create a surface to plant on
+ surface_entity = dynveg.create_surface_entity("Planting Surface", center_point, 128.0, 128.0, 1.0)
+ Report.result(Tests.surface_entity_created, surface_entity.id.IsValid())
- # 5) Move the default Camera entity for testing in the launcher
- cam_position = math.Vector3(512.0, 500.0, 35.0)
- search_filter = entity.SearchFilter()
- search_filter.names = ["Camera"]
- search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
- components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
+ # 4) Verify instance counts are accurate
+ num_expected_instances = 20 * 20
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected_instances), 5.0)
+ Report.result(Tests.instance_count, success)
- # 6) Save and export to engine
- general.save_level()
- general.idle_wait(1.0)
- general.export_to_engine()
- general.idle_wait(1.0)
+ # 5) Move the default Camera entity for testing in the launcher
+ cam_position = math.Vector3(512.0, 500.0, 35.0)
+ search_filter = entity.SearchFilter()
+ search_filter.names = ["Camera"]
+ search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
+ components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
+
+ # 6) Save and export to engine
+ general.save_level()
+ general.export_to_engine()
+ pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
+ Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
-test = TestDynamicSliceInstanceSpawnerEmbeddedEditor()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(DynamicSliceInstanceSpawner_Embedded_E2E)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py
index dfa4d8191e..7a0abdd969 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py
@@ -5,122 +5,137 @@ 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.legacy.general as general
-import azlmbr.asset as asset
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.entity as entity
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ level_created = (
+ "Successfully created level",
+ "Failed to create level"
+ )
+ spawner_entity_created = (
+ "Spawner entity created successfully",
+ "Failed to create spawner entity"
+ )
+ surface_entity_created = (
+ "Surface entity created successfully",
+ "Failed to create surface entity"
+ )
+ instance_count = (
+ "Found the expected number of instances",
+ "Found an unexpected number of instances"
+ )
+ saved_and_exported = (
+ "Saved and exported level successfully",
+ "Failed to save and export level"
+ )
-class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="DynamicSliceInstanceSpawnerExternalEditor", args=["level"])
+def DynamicSliceInstanceSpawner_External_E2E():
+ """
+ Summary:
+ A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
+ Dynamic Slice Instance Spawner type using external assets.
- def run_test(self):
- """
- Summary:
- A new temporary level is created. Surface for planting is created. Simple vegetation area is created using
- Dynamic Slice Instance Spawner type using external assets.
+ Expected Behavior:
+ Instances plant as expected in the assigned area.
- Expected Behavior:
- Instances plant as expected in the assigned area.
+ Test Steps:
+ 1) Create level
+ 2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
+ 3) Create a surface to plant on
+ 4) Verify expected instance counts
+ 5) Add a camera component looking at the planting area for visual debugging
+ 6) Save and export to engine
- Test Steps:
- 1) Create level
- 2) Create a Vegetation Layer Spawner setup using Dynamic Slice Instance Spawner type assets
- 3) Create a surface to plant on
- 4) Verify expected instance counts
- 5) Add a camera component looking at the planting area for visual debugging
- 6) Save and export to engine
+ 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
- # 1) Create a new, temporary 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 azlmbr.asset as asset
+ import azlmbr.components as components
+ import azlmbr.editor as editor
+ import azlmbr.entity as entity
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
+ import azlmbr.paths as paths
- general.set_current_view_position(512.0, 480.0, 38.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components and switch the Vegetation Asset List Source
- # Type to External
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List",
- "Script Canvas"]
- new_entity_id = editor.ToolsApplicationRequestBus(
- bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
- )
- if new_entity_id.IsValid():
- self.log("Spawner entity created")
- spawner_entity = hydra.Entity("Spawner Entity", new_entity_id)
- spawner_entity.components = []
- for component in veg_area_required_components:
- spawner_entity.components.append(hydra.add_component(component, new_entity_id))
- hydra.get_set_test(spawner_entity, 2, "Configuration|Source Type", 1)
+ # 1) Create a new, temporary level
+ lvl_name = "tmp_level"
+ helper.init_idle()
+ level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
+ general.idle_wait(1.0)
+ Report.critical_result(Tests.level_created, level_created == 0)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Add a Script Canvas component with instance_counter script for launcher tests
- instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
- instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
- math.Uuid(), False)
- spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
+ # 2) Create a new entity with required vegetation area components and switch the Vegetation Asset List Source
+ # Type to External
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List",
+ "Script Canvas"]
+ new_entity_id = editor.ToolsApplicationRequestBus(
+ bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
+ )
+ spawner_entity = hydra.Entity("Spawner Entity", new_entity_id)
+ spawner_entity.components = []
+ for component in veg_area_required_components:
+ spawner_entity.components.append(hydra.add_component(component, new_entity_id))
+ hydra.get_set_test(spawner_entity, 2, "Configuration|Source Type", 1)
- # Assign a Vegetation Descriptor List asset to the Vegetation Asset List component
- descriptor_asset = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", os.path.join("Assets", "VegDescriptorLists", "flower_pink.vegdescriptorlist"), math.Uuid(),
- False)
- hydra.get_set_test(spawner_entity, 2, "Configuration|External Assets", descriptor_asset)
+ # Add a Script Canvas component with instance_counter script for launcher tests
+ instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas")
+ instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
+ math.Uuid(), False)
+ spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script)
+ Report.result(Tests.spawner_entity_created, spawner_entity.id.IsValid() and hydra.has_components(spawner_entity.id,
+ ["Script Canvas"]))
- # Resize the Box Shape component
- new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
- box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
- hydra.get_set_test(spawner_entity, 1, box_dimensions_path, new_box_dimensions)
+ # Assign a Vegetation Descriptor List asset to the Vegetation Asset List component
+ descriptor_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", os.path.join("Assets", "VegDescriptorLists", "flower_pink.vegdescriptorlist"), math.Uuid(),
+ False)
+ hydra.get_set_test(spawner_entity, 2, "Configuration|External Assets", descriptor_asset)
- # 3) Create a surface to plant on
- dynveg.create_surface_entity("Planting Surface", entity_position, 128.0, 128.0, 1.0)
+ # Resize the Box Shape component
+ new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
+ box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
+ hydra.get_set_test(spawner_entity, 1, box_dimensions_path, new_box_dimensions)
- # 4) Verify instance counts are accurate
- general.idle_wait(3.0) # Allow a few seconds for instances to spawn
- num_expected_instances = 20 * 20
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
- self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
- self.test_success = self.test_success and num_found == num_expected_instances
+ # 3) Create a surface to plant on
+ surface_entity = dynveg.create_surface_entity("Planting Surface", entity_position, 128.0, 128.0, 1.0)
+ Report.result(Tests.surface_entity_created, surface_entity.id.IsValid())
- # 5) Move the default Camera entity for testing in the launcher
- cam_position = math.Vector3(512.0, 500.0, 35.0)
- search_filter = entity.SearchFilter()
- search_filter.names = ["Camera"]
- search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
- components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
+ # 4) Verify instance counts are accurate
+ num_expected_instances = 20 * 20
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected_instances), 5.0)
+ Report.result(Tests.instance_count, success)
- # 6) Save and export to engine
- general.save_level()
- general.idle_wait(1.0)
- general.export_to_engine()
- general.idle_wait(1.0)
+ # 5) Move the default Camera entity for testing in the launcher
+ cam_position = math.Vector3(512.0, 500.0, 35.0)
+ search_filter = entity.SearchFilter()
+ search_filter.names = ["Camera"]
+ search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
+ components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
+
+ # 6) Save and export to engine
+ general.save_level()
+ general.export_to_engine()
+ pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
+ Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
-test = TestDynamicSliceInstanceSpawnerExternalEditor()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(DynamicSliceInstanceSpawner_External_E2E)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py
index 721d06f858..d0a51809b4 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py
@@ -5,109 +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.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class BehaviorContextTests:
+ spawner_initialized = (
+ "Successfully initialized an Empty Instance Spawner",
+ "Failed to initialize an Empty Instance Spawner"
+ )
+ desc_spawnertype_sets_spawner = (
+ "Setting spawnerType sets spawner too",
+ "Setting spawnerType failed to set spawner to expected value"
+ )
+ desc_spawner_sets_spawnertype = (
+ "Setting spawner sets spawnerType too",
+ "Setting spawner failed to set spawnerType to expected value"
+ )
-class TestEmptyInstanceSpawner(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="EmptyInstanceSpawner", args=["level"])
+class PropertyTreeTests:
+ entity_created = (
+ "Spawner entity created successfully",
+ "Failed to create spawner entity"
+ )
+ spawner_type_set = (
+ "Successfully set spawner type",
+ "Failed to set spawner type"
+ )
+ empty_instance_count_validation = (
+ "Expected number of empty instances planted",
+ "Unexpected number of empty instances planted"
+ )
+ not_affected_by_allow_empty_assets = (
+ "Instance count unaffected by Allow Empty Assets toggle",
+ "Instance count was unexpectedly affected by Allow Empty Assets toggle"
+ )
- def run_test(self):
- """
- Summary:
- Test aspects of the EmptyInstanceSpawner through the BehaviorContext and the Property Tree.
- :return: None
- """
- # 1) Open an 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 EmptyInstanceSpawner_EmptySpawnerWorks():
+ """
+ Summary:
+ Test aspects of the EmptyInstanceSpawner through the BehaviorContext and the Property Tree.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+ general.set_current_view_position(512.0, 480.0, 38.0)
+
+ # Grab the UUID that we need for creating an Empty Spawner
+ empty_spawner_uuid = azlmbr.math.Uuid_CreateString('{23C40FD4-A55F-4BD3-BE5B-DC5423F217C2}', 0)
+
+ # 2) Test EmptyInstanceSpawner BehaviorContext
+ behavior_context_test_success = True
+ empty_spawner = azlmbr.vegetation.EmptyInstanceSpawner()
+ behavior_context_test_success = behavior_context_test_success and (empty_spawner is not None)
+ behavior_context_test_success = behavior_context_test_success and (empty_spawner.typename == 'EmptyInstanceSpawner')
+ Report.critical_result(BehaviorContextTests.spawner_initialized, behavior_context_test_success)
+ Report.info(f'EmptyInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
+
+ # 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
+ spawner_type_test_success = True
+ descriptor = azlmbr.vegetation.Descriptor()
+ spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', empty_spawner_uuid)
+ spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
+ Report.result(BehaviorContextTests.desc_spawnertype_sets_spawner, spawner_type_test_success)
+ Report.info(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
+
+ # 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
+ spawner_test_success = True
+ descriptor = azlmbr.vegetation.Descriptor()
+ descriptor.spawner = empty_spawner
+ spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(empty_spawner_uuid))
+ spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
+ Report.result(BehaviorContextTests.desc_spawner_sets_spawnertype, spawner_test_success)
+ Report.info(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
+
+ ### Setup for Property Tree set of tests
+
+ # Create a new entity with required vegetation area components
+ spawner_entity = hydra.Entity("Veg Area")
+ spawner_entity.create_entity(
+ math.Vector3(512.0, 512.0, 32.0),
+ ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
)
- general.idle_wait(1.0)
- general.set_current_view_position(512.0, 480.0, 38.0)
+ Report.critical_result(PropertyTreeTests.entity_created, spawner_entity.id.IsValid())
- # Grab the UUID that we need for creating an Empty Spawner
- empty_spawner_uuid = azlmbr.math.Uuid_CreateString('{23C40FD4-A55F-4BD3-BE5B-DC5423F217C2}', 0)
+ # Resize the Box Shape component
+ new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
+ box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
+ spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
- # 2) Test EmptyInstanceSpawner BehaviorContext
- behavior_context_test_success = True
- empty_spawner = azlmbr.vegetation.EmptyInstanceSpawner()
- behavior_context_test_success = behavior_context_test_success and (empty_spawner is not None)
- behavior_context_test_success = behavior_context_test_success and (empty_spawner.typename == 'EmptyInstanceSpawner')
- self.test_success = self.test_success and behavior_context_test_success
- self.log(f'EmptyInstanceSpawner() BehaviorContext test: {behavior_context_test_success}')
+ # Create a surface to plant on
+ dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
- # 3) Test Descriptor BehaviorContext - setting spawnerType sets spawner too
- spawner_type_test_success = True
- descriptor = azlmbr.vegetation.Descriptor()
- spawner_type_test_success = spawner_type_test_success and hydra.get_set_property_test(descriptor, 'spawnerType', empty_spawner_uuid)
- spawner_type_test_success = spawner_type_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
- self.test_success = self.test_success and spawner_type_test_success
- self.log(f'Descriptor() BehaviorContext spawnerType test: {spawner_type_test_success}')
+ # 5) Descriptor Property Tree test: spawner type can be set
- # 4) Test Descriptor BehaviorContext - setting spawner sets spawnerType too
- spawner_test_success = True
- descriptor = azlmbr.vegetation.Descriptor()
- descriptor.spawner = empty_spawner
- spawner_test_success = spawner_test_success and (descriptor.spawnerType.Equal(empty_spawner_uuid))
- spawner_test_success = spawner_test_success and (descriptor.spawner.typename == 'EmptyInstanceSpawner')
- self.test_success = self.test_success and spawner_test_success
- self.log(f'Descriptor() BehaviorContext spawner test: {spawner_test_success}')
+ # - Validate the empty spawner type can be set correctly.
+ property_tree_success = True
+ property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', empty_spawner_uuid)
+ Report.result(PropertyTreeTests.spawner_type_set, property_tree_success)
- ### Setup for Property Tree set of tests
+ # This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
+ # 20 instances per 16 meters
+ num_expected_instances = 20 * 20
+ property_tree_success = property_tree_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(PropertyTreeTests.empty_instance_count_validation, property_tree_success)
+ Report.info(f'Property Tree spawner type test: {property_tree_success}')
- # Create a new entity with required vegetation area components
- spawner_entity = hydra.Entity("Veg Area")
- spawner_entity.create_entity(
- math.Vector3(512.0, 512.0, 32.0),
- ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
- )
- if spawner_entity.id.IsValid():
- self.log(f"'{spawner_entity.name}' created")
-
- # Resize the Box Shape component
- new_box_dimensions = math.Vector3(16.0, 16.0, 16.0)
- box_dimensions_path = "Box Shape|Box Configuration|Dimensions"
- spawner_entity.get_set_test(1, box_dimensions_path, new_box_dimensions)
-
- # Create a surface to plant on
- dynveg.create_surface_entity("Surface Entity", math.Vector3(512.0, 512.0, 32.0), 1024.0, 1024.0, 1.0)
-
- # 5) Descriptor Property Tree test: spawner type can be set
-
- # - Validate the empty spawner type can be set correctly.
- property_tree_success = True
- property_tree_success = property_tree_success and spawner_entity.get_set_test(2, 'Configuration|Embedded Assets|[0]|Instance Spawner', empty_spawner_uuid)
-
- # This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
- # 20 instances per 16 meters
- num_expected_instances = 20 * 20
- property_tree_success = property_tree_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = self.test_success and property_tree_success
- self.log(f'Property Tree spawner type test: {property_tree_success}')
-
- # 6) Validate that the "Allow Empty Assets" setting doesn't affect the EmptyInstanceSpawner
- allow_empty_assets_success = True
- spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
- allow_empty_assets_success = allow_empty_assets_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
- self.test_success = self.test_success and allow_empty_assets_success
- self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
+ # 6) Validate that the "Allow Empty Assets" setting doesn't affect the EmptyInstanceSpawner
+ allow_empty_assets_success = True
+ spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
+ allow_empty_assets_success = allow_empty_assets_success and helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
+ Report.result(PropertyTreeTests.not_affected_by_allow_empty_assets, allow_empty_assets_success)
+ Report.info(f'Allow Empty Assets test: {allow_empty_assets_success}')
-test = TestEmptyInstanceSpawner()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(EmptyInstanceSpawner_EmptySpawnerWorks)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py
index e5ff0bf86f..98418c2432 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py
@@ -5,111 +5,115 @@ 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.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-import azlmbr.math as math
-import azlmbr.paths
-import azlmbr.vegetation as vegetation
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_instance_count = (
+ "Initial instance count is as expected",
+ "Initial instance count does not match expected results"
+ )
+ layer_priority_instance_count = (
+ "Instance count is as expected after updating layer priorities",
+ "Instance count does not match expected results after updating layer priorities"
+ )
+ sub_priority_instance_count = (
+ "Instance count is as expected after updating sub priorities",
+ "Instance count does not match expected results after updating sub priorities"
+ )
-class TestInstanceSpawnerPriority(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="InstanceSpawnerPriority", args=["level"])
+def InstanceSpawnerPriority_LayerAndSubPriority():
+ """
+ Summary:
+ A new level is created. An instance spawner area and blocker area are setup to overlap. Instance counts are
+ verified with the initial setup. Layer priority on the blocker area is set to lower than the instance spawner
+ area, and instance counts are re-verified.
- def run_test(self):
- """
- Summary:
- A new level is created. An instance spawner area and blocker area are setup to overlap. Instance counts are
- verified with the initial setup. Layer priority on the blocker area is set to lower than the instance spawner
- area, and instance counts are re-verified.
+ Expected Behavior:
+ Vegetation areas with a higher Layer Priority plant over those with a lower Layer Priority
- Expected Behavior:
- Vegetation areas with a higher Layer Priority plant over those with a lower Layer Priority
+ Test Steps:
+ 1) Open a simple level
+ 2) Create overlapping instance spawner and blocker areas
+ 3) Create a surface to plant on
+ 4) Validate initial instance counts in the spawner area
+ 5) Reduce the Layer Priority of the blocker area
+ 6) Validate instance counts in the spawner area
- Test Steps:
- 1) Create a new level
- 2) Create overlapping instance spawner and blocker areas
- 3) Create a surface to plant on
- 4) Validate initial instance counts in the spawner area
- 5) Reduce the Layer Priority of the blocker area
- 6) Validate instance counts in the spawner area
-
- 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 a new, temporary 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
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- # 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
- spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
- asset_path)
- blocker_center_point = math.Vector3(516.0, 516.0, 32.0)
- blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 3) Create a surface for planting
- planting_surface_center_point = math.Vector3(512.0, 512.0, 32.0)
- dynveg.create_surface_entity("Planting Surface", planting_surface_center_point, 64.0, 64.0, 1.0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 4) Validate the expected instance count with initial setup. GetAreaProductCount is used as
- # GetInstanceCountInAabb does not filter out blocked instances
- num_expected = (20 * 20) - (10 * 10) # 20 instances per 16m per side minus 1 blocked quadrant
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = self.test_success and result
+ # 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area
+ spawner_center_point = math.Vector3(508.0, 508.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0,
+ asset_path)
+ blocker_center_point = math.Vector3(516.0, 516.0, 32.0)
+ blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0)
- # 5) Change the Instance Spawner area to a higher layer priority than the Instance Blocker
- blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 0)
+ # 3) Create a surface for planting
+ planting_surface_center_point = math.Vector3(512.0, 512.0, 32.0)
+ dynveg.create_surface_entity("Planting Surface", planting_surface_center_point, 64.0, 64.0, 1.0)
- # 6) Validate the expected instance count with changed area priorities
- num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = self.test_success and result
+ # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- # 7) Revert Layer Priority changes so both areas are equal, and change Sub Priority to a higher value on the
- # Instance Spawner area
- blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 1)
- spawner_entity.get_set_test(0, 'Configuration|Sub Priority', 100)
- blocker_entity.get_set_test(0, 'Configuration|Sub Priority', 1)
+ # 4) Validate the expected instance count with initial setup. GetAreaProductCount is used as
+ # GetInstanceCountInAabb does not filter out blocked instances
+ num_expected = (20 * 20) - (10 * 10) # 20 instances per 16m per side minus 1 blocked quadrant
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.initial_instance_count, result)
- # 8) Validate the expected instance count with changed area priorities
- num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = self.test_success and result
+ # 5) Change the Instance Spawner area to a higher layer priority than the Instance Blocker
+ blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 0)
+
+ # 6) Validate the expected instance count with changed area priorities
+ num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.layer_priority_instance_count, result)
+
+ # 7) Revert Layer Priority changes so both areas are equal, and change Sub Priority to a higher value on the
+ # Instance Spawner area
+ blocker_entity.get_set_test(0, 'Configuration|Layer Priority', 1)
+ spawner_entity.get_set_test(0, 'Configuration|Sub Priority', 100)
+ blocker_entity.get_set_test(0, 'Configuration|Sub Priority', 1)
+
+ # 8) Validate the expected instance count with changed area priorities
+ num_expected = 20 * 20 # 20 instances per 16m per side, no instances should be blocked at this point
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.sub_priority_instance_count, result)
-test = TestInstanceSpawnerPriority()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(InstanceSpawnerPriority_LayerAndSubPriority)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
index f03ea29613..f56c0b836e 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
@@ -5,151 +5,161 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C2627906: A simple Vegetation Layer Blender area can be created
-"""
-import os
-from math import radians
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.asset as asset
-import azlmbr.areasystem as areasystem
-import azlmbr.legacy.general as general
-import azlmbr
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.math as math
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ level_created = (
+ "Successfully created level",
+ "Failed to create level"
+ )
+ blender_entity_created = (
+ "Blender entity created successfully",
+ "Failed to create Blender entity"
+ )
+ instance_count = (
+ "Found the expected number of instances in the Blender area",
+ "Found an unexpected number of instances in the Blender area"
+ )
+ instances_blended = (
+ "Instances from each spawner are blended as expected",
+ "Found an unexpected number of instances from each spawner"
+ )
+ saved_and_exported = (
+ "Saved and exported level successfully",
+ "Failed to save and export level"
+ )
-class TestVegLayerBlenderCreated(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="LayerBlender_E2E_Editor", args=["level"])
- self.screenshot_count = 0
+def LayerBlender_E2E_Editor():
+ """
+ Summary:
+ A temporary level is loaded. Two vegetation areas with different meshes are added and then
+ pinned to a vegetation blender. Screenshots are taken in the editor normal mode and in game mode.
- def run_test(self):
- """
- Summary:
- A temporary level is loaded. Two vegetation areas with different meshes are added and then
- pinned to a vegetation blender. Screenshots are taken in the editor normal mode and in game mode.
+ Expected Behavior:
+ The specified assets plant in the specified blend area and are visible in the Viewport in
+ Edit Mode, Game Mode.
- Expected Behavior:
- The specified assets plant in the specified blend area and are visible in the Viewport in
- Edit Mode, Game Mode.
+ Test Steps:
+ 1) Create level
+ 2) Create 2 vegetation areas with different meshes
+ 3) Create Blender entity and pin the vegetation areas
+ 4) Take screenshot in normal mode
+ 5) Create a new entity with a Camera component for testing in the launcher
+ 6) Save level and take screenshot in game mode
+ 7) Export to engine
- Test Steps:
- 1) Create level
- 2) Create 2 vegetation areas with different meshes
- 3) Create Blender entity and pin the vegetation areas
- 4) Take screenshot in normal mode
- 5) Create a new entity with a Camera component for testing in the launcher
- 6) Save level and take screenshot in game mode
- 7) Export to engine
+ 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
+ from math import radians
- # 1) Create/prepare a new level and set an appropriate view of blender area
- 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 azlmbr.asset as asset
+ import azlmbr.areasystem as areasystem
+ import azlmbr.legacy.general as general
+ import azlmbr.paths as paths
+ import azlmbr.bus as bus
+ import azlmbr.components as components
+ import azlmbr.math as math
+ import azlmbr.entity as entity
- general.set_current_view_position(500.49, 498.69, 46.66)
- general.set_current_view_rotation(-42.05, 0.00, -36.33)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create 2 vegetation areas with different meshes
- purple_position = math.Vector3(504.0, 512.0, 32.0)
- purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity_1 = dynveg.create_vegetation_area("Purple Spawner",
- purple_position,
- 16.0, 16.0, 1.0,
- purple_asset_path)
+ # 1) Create a new, temporary level
+ lvl_name = "tmp_level"
+ helper.init_idle()
+ level_created = general.create_level_no_prompt(lvl_name, 1024, 1, 4096, False)
+ general.idle_wait(1.0)
+ Report.critical_result(Tests.level_created, level_created == 0)
- pink_position = math.Vector3(520.0, 512.0, 32.0)
- pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity_2 = dynveg.create_vegetation_area("Pink Spawner",
- pink_position,
- 16.0, 16.0, 1.0,
- pink_asset_path)
+ general.set_current_view_position(500.49, 498.69, 46.66)
+ general.set_current_view_rotation(-42.05, 0.00, -36.33)
- base_position = math.Vector3(512.0, 512.0, 32.0)
- dynveg.create_surface_entity("Surface Entity",
- base_position,
- 16.0, 16.0, 1.0)
+ # 2) Create 2 vegetation areas with different meshes
+ purple_position = math.Vector3(504.0, 512.0, 32.0)
+ purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity_1 = dynveg.create_vegetation_area("Purple Spawner",
+ purple_position,
+ 16.0, 16.0, 1.0,
+ purple_asset_path)
- hydra.add_level_component("Vegetation Debugger")
+ pink_position = math.Vector3(520.0, 512.0, 32.0)
+ pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity_2 = dynveg.create_vegetation_area("Pink Spawner",
+ pink_position,
+ 16.0, 16.0, 1.0,
+ pink_asset_path)
- # 3) Create Blender entity and pin the vegetation areas. We also add and attach a Lua script to validate in the
- # launcher for the follow-up test
- blender_entity = hydra.Entity("Blender")
- blender_entity.create_entity(
- base_position,
- ["Box Shape", "Vegetation Layer Blender", "Lua Script"]
- )
- if blender_entity.id.IsValid():
- print(f"'{blender_entity.name}' created")
+ base_position = math.Vector3(512.0, 512.0, 32.0)
+ dynveg.create_surface_entity("Surface Entity",
+ base_position,
+ 16.0, 16.0, 1.0)
- blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
- blender_entity.get_set_test(1, "Configuration|Vegetation Areas", [spawner_entity_1.id, spawner_entity_2.id])
- instance_counter_path = os.path.join("luascripts", "instance_counter_blender.lua")
- instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
- math.Uuid(), False)
- blender_entity.get_set_test(2, "Script properties|Asset", instance_counter_script)
+ hydra.add_level_component("Vegetation Debugger")
- # 4) Verify instances in blender area are equally represented by both descriptors
+ # 3) Create Blender entity and pin the vegetation areas. We also add and attach a Lua script to validate in the
+ # launcher for the follow-up test
+ blender_entity = hydra.Entity("Blender")
+ blender_entity.create_entity(
+ base_position,
+ ["Box Shape", "Vegetation Layer Blender", "Lua Script"]
+ )
+ Report.result(Tests.blender_entity_created, blender_entity.id.IsValid())
- # Wait for instances to spawn
- general.run_console('veg_debugClearAllAreas')
- num_expected = 20 * 20
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count(base_position, 8.0, num_expected), 5.0)
+ blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
+ blender_entity.get_set_test(1, "Configuration|Vegetation Areas", [spawner_entity_1.id, spawner_entity_2.id])
+ instance_counter_path = os.path.join("luascripts", "instance_counter_blender.lua")
+ instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path,
+ math.Uuid(), False)
+ blender_entity.get_set_test(2, "Script properties|Asset", instance_counter_script)
- if self.test_success:
- box = math.Aabb_CreateCenterRadius(base_position, 8.0)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- pink_count = 0
- purple_count = 0
- for instance in instances:
- purple_asset_path = purple_asset_path.replace("\\", "/").lower()
- pink_asset_path = pink_asset_path.replace("\\", "/").lower()
- if instance.descriptor.spawner.GetSliceAssetPath() == pink_asset_path:
- pink_count += 1
- elif instance.descriptor.spawner.GetSliceAssetPath() == purple_asset_path:
- purple_count += 1
- self.test_success = pink_count == purple_count and (pink_count + purple_count == num_expected) and self.test_success
+ # 4) Verify instances in blender area are equally represented by both descriptors
- # 5) Move the default Camera entity for testing in the launcher
- cam_position = math.Vector3(500.0, 500.0, 47.0)
- cam_rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
- search_filter = entity.SearchFilter()
- search_filter.names = ["Camera"]
- search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
- components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
- azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector)
+ # Wait for instances to spawn
+ general.run_console('veg_debugClearAllAreas')
+ num_expected = 20 * 20
+ success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count(base_position, 8.0, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, success)
- # 6) Save and export level
- general.save_level()
- general.idle_wait(1.0)
- general.export_to_engine()
- general.idle_wait(1.0)
+ box = math.Aabb_CreateCenterRadius(base_position, 8.0)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ pink_count = 0
+ purple_count = 0
+ for instance in instances:
+ purple_asset_path = purple_asset_path.replace("\\", "/").lower()
+ pink_asset_path = pink_asset_path.replace("\\", "/").lower()
+ if instance.descriptor.spawner.GetSliceAssetPath() == pink_asset_path:
+ pink_count += 1
+ elif instance.descriptor.spawner.GetSliceAssetPath() == purple_asset_path:
+ purple_count += 1
+ Report.result(Tests.instances_blended, pink_count == purple_count and (pink_count + purple_count == num_expected))
+
+ # 5) Move the default Camera entity for testing in the launcher
+ cam_position = math.Vector3(500.0, 500.0, 47.0)
+ cam_rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
+ search_filter = entity.SearchFilter()
+ search_filter.names = ["Camera"]
+ search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
+ components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
+ azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector)
+
+ # 6) Save and export to engine
+ general.save_level()
+ general.export_to_engine()
+ pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
+ Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
-test = TestVegLayerBlenderCreated()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(LayerBlender_E2E_Editor)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py
index 138ac27700..625b7d2265 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py
@@ -5,102 +5,105 @@ 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.math as math
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_instance_count = (
+ "Initial instance count is as expected",
+ "Unexpected number of initial instances found"
+ )
+ blocked_instance_count = (
+ "Expected number of instances found after configuring Blocker",
+ "Unexpected number of instances found after configuring Blocker"
+ )
-class TestLayerBlocker(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="LayerBlocker_InstancesBlocked", args=["level"])
- def run_test(self):
- """
- Summary:
- An empty level is created. A Vegetation Layer Spawner area is configured. A Vegetation Layer Blocker area is
- configured to block instances in the spawner area.
+def LayerBlocker_InstancesBlockedInConfiguredArea():
+ """
+ Summary:
+ An empty level is created. A Vegetation Layer Spawner area is configured. A Vegetation Layer Blocker area is
+ configured to block instances in the spawner area.
- Expected Behavior:
- Vegetation is blocked by the configured Blocker area.
+ Expected Behavior:
+ Vegetation is blocked by the configured Blocker area.
- Test Steps:
- 1. A new level is created
- 2. Vegetation Layer Spawner area is created
- 3. Planting surface is created
- 4. Vegetation System Settings level component is added, and Snap Mode set to center to ensure expected instance
- counts are accurate in the configured vegetation area
- 5. Initial instance counts pre-blocker are validated
- 6. A Vegetation Layer Blocker area is created, overlapping the spawner area
- 7. Post-blocker instance counts are validated
+ Test Steps:
+ 1. A simple level is opened
+ 2. Vegetation Layer Spawner area is created
+ 3. Planting surface is created
+ 4. Vegetation System Settings level component is added, and Snap Mode set to center to ensure expected instance
+ counts are accurate in the configured vegetation area
+ 5. Initial instance counts pre-blocker are validated
+ 6. A Vegetation Layer Blocker area is created, overlapping the spawner area
+ 7. Post-blocker instance counts are validated
- 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 a new, temporary 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
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.math as math
+ import azlmbr.legacy.general as general
- # 2) Create a new instance spawner entity
- spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
- asset_path)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 3) Create surface for planting on
- dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 5) Verify initial instance counts
- num_expected = 20 * 20
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ # 2) Create a new instance spawner entity
+ spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+ asset_path)
- # 6) Create a new Vegetation Layer Blocker area overlapping the spawner area
- blocker_entity = hydra.Entity("Blocker Area")
- blocker_entity.create_entity(
- spawner_center_point,
- ["Vegetation Layer Blocker", "Box Shape"]
- )
- if blocker_entity.id.IsValid():
- print(f"'{blocker_entity.name}' created")
- blocker_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions",
- math.Vector3(3.0, 3.0, 3.0))
+ # 3) Create surface for planting on
+ dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0)
- # 7) Validate instance counts post-blocker. 16 instances should now be blocked in the center of the spawner area
- num_expected = (20 * 20) - 16
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ # 4) Add a Vegetation System Settings Level component and set Sector Point Snap Mode to Center
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+
+ # 5) Verify initial instance counts
+ num_expected = 20 * 20
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.initial_instance_count, success)
+
+ # 6) Create a new Vegetation Layer Blocker area overlapping the spawner area
+ blocker_entity = hydra.Entity("Blocker Area")
+ blocker_entity.create_entity(
+ spawner_center_point,
+ ["Vegetation Layer Blocker", "Box Shape"]
+ )
+ if blocker_entity.id.IsValid():
+ print(f"'{blocker_entity.name}' created")
+ blocker_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions",
+ math.Vector3(3.0, 3.0, 3.0))
+
+ # 7) Validate instance counts post-blocker. 16 instances should now be blocked in the center of the spawner area
+ num_expected = (20 * 20) - 16
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.blocked_instance_count, success)
-test = TestLayerBlocker()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(LayerBlocker_InstancesBlockedInConfiguredArea)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py
index a52f91ae5f..8592692c4b 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py
@@ -5,85 +5,83 @@ 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.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ preprocess_instance_count = (
+ "Preprocess filter stage vegetation instance count is as expected",
+ "Preprocess filter stage instance count found an unexpected number of instances"
+ )
+ postprocess_instance_count = (
+ "Postprocess filter stage vegetation instance count is as expected",
+ "Postprocess filter stage instance count found an unexpected number of instances"
+ )
-class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="LayerSpawner_FilterStageToggle", args=["level"])
+def LayerSpawner_FilterStageToggle():
+ """
+ Summary:
+ Filter Stage toggle affects final vegetation position.
- def run_test(self):
- """
- Summary:
- C4765973 Filter Stage toggle affects final vegetation position.
+ Expected Result:
+ Vegetation instances plant differently depending on the Filter Stage setting.
- Expected Result:
- Vegetation instances plant differently depending on the Filter Stage setting.
+ :return: None
+ """
- :return: None
- """
+ import os
- PREPROCESS_INSTANCE_COUNT = 21
- POSTPROCESS_INSTANCE_COUNT = 19
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # 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,
- )
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- general.set_current_view_position(500.49, 498.69, 46.66)
- general.set_current_view_rotation(-42.05, 0.00, -36.33)
+ PREPROCESS_INSTANCE_COUNT = 21
+ POSTPROCESS_INSTANCE_COUNT = 19
- # Create a vegetation area with all needed components
- position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
- vegetation_entity.add_component("Vegetation Altitude Filter")
- vegetation_entity.add_component("Vegetation Position Modifier")
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create a child entity under vegetation area
- child_entity = hydra.Entity("child_entity")
- components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"]
- child_entity.create_entity(position, components_to_add, vegetation_entity.id)
+ general.set_current_view_position(500.49, 498.69, 46.66)
+ general.set_current_view_rotation(-42.05, 0.00, -36.33)
- # Set the Gradient Id in X and Y direction
- vegetation_entity.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", child_entity.id)
- vegetation_entity.get_set_test(4, "Configuration|Position Y|Gradient|Gradient Entity Id", child_entity.id)
+ # Create a vegetation area with all needed components
+ position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ vegetation_entity = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
+ vegetation_entity.add_component("Vegetation Altitude Filter")
+ vegetation_entity.add_component("Vegetation Position Modifier")
- # Set the min and max values for Altitude Filter
- vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 34.0)
- vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 38.0)
+ # Create a child entity under vegetation area
+ child_entity = hydra.Entity("child_entity")
+ components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"]
+ child_entity.create_entity(position, components_to_add, vegetation_entity.id)
- # Add entity with Mesh to replicate creation of hills and a flat surface to plant on
- dynveg.create_surface_entity("Flat Surface", position, 32.0, 32.0, 1.0)
- hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0)
+ # Set the Gradient Id in X and Y direction
+ vegetation_entity.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", child_entity.id)
+ vegetation_entity.get_set_test(4, "Configuration|Position Y|Gradient|Gradient Entity Id", child_entity.id)
- # Set the filter stage to preprocess and postprocess respectively and verify instance count
- vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)
- self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, PREPROCESS_INSTANCE_COUNT), 3.0)
- result = dynveg.validate_instance_count(position, 16.0, PREPROCESS_INSTANCE_COUNT)
- self.log(f"Preprocess filter stage vegetation instance count is as expected: {result}")
- vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 2)
- self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, POSTPROCESS_INSTANCE_COUNT), 3.0)
- result = dynveg.validate_instance_count(position, 16.0, POSTPROCESS_INSTANCE_COUNT)
- self.log(f"Postprocess filter vegetation instance stage count is as expected: {result}")
+ # Set the min and max values for Altitude Filter
+ vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 34.0)
+ vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 38.0)
+
+ # Add entity with Mesh to replicate creation of hills and a flat surface to plant on
+ dynveg.create_surface_entity("Flat Surface", position, 32.0, 32.0, 1.0)
+ hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0)
+
+ # Set the filter stage to preprocess and postprocess respectively and verify instance count
+ vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, PREPROCESS_INSTANCE_COUNT), 3.0)
+ Report.result(Tests.preprocess_instance_count, result)
+ vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 2)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, POSTPROCESS_INSTANCE_COUNT), 3.0)
+ Report.result(Tests.postprocess_instance_count, result)
-test = TestLayerSpawnerFilterStageToggle()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(LayerSpawner_FilterStageToggle)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py
index 5e5c6410b0..649c7d0776 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py
@@ -5,118 +5,116 @@ 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.legacy.general as general
-import azlmbr.paths
-import azlmbr.surface_data as surface_data
-import azlmbr.vegetation as vegetation
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ inherit_behavior_checked = (
+ "Found no instances with Inherit Behavior checked as expected",
+ "Unexpectedly found instances with Inherit Behavior checked"
+ )
+ inherit_behavior_unchecked = (
+ "Found instances with Inherit Behavior unchecked as expected",
+ "Unexpectedly found no instances with Inherit Behavior unchecked"
+ )
-class TestLayerSpawnerInheritBehavior(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="LayerSpawner_InheritBehavior", args=["level"])
+def LayerSpawner_InheritBehaviorFlag():
+ """
+ Summary:
+ Verifies if Inherit Behavior Flag works as expected.
- def run_test(self):
- """
- Summary:
- C4762381 Verifies if Inherit Behavior Flag works as expected.
+ Expected Result:
+ The spawner with Inherit Behavior toggled off no longer obeys
+ Vegetation Surface Mask Filter of the Vegetation Layer Blender entity and plants on the surface.
- Expected Result:
- The spawner with Inherit Behavior toggled off no longer obeys
- Vegetation Surface Mask Filter of the Vegetation Layer Blender entity and plants on the surface.
+ :return: None
+ """
+ import os
- :return: None
- """
+ import azlmbr.math as math
+ import azlmbr.legacy.general as general
+ import azlmbr.surface_data as surface_data
+ import azlmbr.vegetation as vegetation
- SURFACE_TAG = "test_tag"
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- def set_dynamic_slice_asset(entity_obj, component_index, dynamic_slice_asset_path):
- dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
- dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
- descriptor = hydra.get_component_property_value(
- entity_obj.components[component_index], "Configuration|Embedded Assets|[0]"
- )
- descriptor.spawner = dynamic_slice_spawner
- entity_obj.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
+ SURFACE_TAG = "test_tag"
- # 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,
+ def set_dynamic_slice_asset(entity_obj, component_index, dynamic_slice_asset_path):
+ dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner()
+ dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path)
+ descriptor = hydra.get_component_property_value(
+ entity_obj.components[component_index], "Configuration|Embedded Assets|[0]"
)
+ descriptor.spawner = dynamic_slice_spawner
+ entity_obj.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
- general.set_current_view_position(512.0, 480.0, 38.0)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create Emitter entity and add the required components
- position = math.Vector3(512.0, 512.0, 32.0)
- emitter_entity = dynveg.create_surface_entity("emitter_entity", position, 16.0, 16.0, 1.0)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Add surface tag to the Surface Tag Emitter
- tag = surface_data.SurfaceTag()
- tag.SetTag(SURFACE_TAG)
- pte = hydra.get_property_tree(emitter_entity.components[1])
- path = "Configuration|Generated Tags"
- pte.add_container_item(path, 0, tag)
- emitter_entity.get_set_test(1, "Configuration|Generated Tags|[0]", tag)
+ # Create Emitter entity and add the required components
+ position = math.Vector3(512.0, 512.0, 32.0)
+ emitter_entity = dynveg.create_surface_entity("emitter_entity", position, 16.0, 16.0, 1.0)
- # Create Blender entity and add required components
- components_to_add = ["Box Shape", "Vegetation Layer Blender"]
- blender_entity = hydra.Entity("blender_entity")
- blender_entity.create_entity(position, components_to_add)
- blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
+ # Add surface tag to the Surface Tag Emitter
+ tag = surface_data.SurfaceTag()
+ tag.SetTag(SURFACE_TAG)
+ pte = hydra.get_property_tree(emitter_entity.components[1])
+ path = "Configuration|Generated Tags"
+ pte.add_container_item(path, 0, tag)
+ emitter_entity.get_set_test(1, "Configuration|Generated Tags|[0]", tag)
- # Create Vegetation area and assign a valid asset
- veg_1 = hydra.Entity("veg_1")
- veg_1.create_entity(
- position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
- )
- set_dynamic_slice_asset(veg_1, 2, os.path.join("Slices", "PinkFlower.dynamicslice"))
- veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
+ # Create Blender entity and add required components
+ components_to_add = ["Box Shape", "Vegetation Layer Blender"]
+ blender_entity = hydra.Entity("blender_entity")
+ blender_entity.create_entity(position, components_to_add)
+ blender_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(16.0, 16.0, 1.0))
- # Create second vegetation area and assign a valid asset
- veg_2 = hydra.Entity("veg_2")
- veg_2.create_entity(
- position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
- )
- set_dynamic_slice_asset(veg_2, 2, os.path.join("Slices", "PurpleFlower.dynamicslice"))
- veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
+ # Create Vegetation area and assign a valid asset
+ veg_1 = hydra.Entity("veg_1")
+ veg_1.create_entity(
+ position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
+ )
+ set_dynamic_slice_asset(veg_1, 2, os.path.join("Slices", "PinkFlower.dynamicslice"))
+ veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
- # Assign the vegetation areas to the Blender entity
- pte = hydra.get_property_tree(blender_entity.components[1])
- path = "Configuration|Vegetation Areas"
- pte.update_container_item(path, 0, veg_1.id)
- pte.add_container_item(path, 1, veg_2.id)
+ # Create second vegetation area and assign a valid asset
+ veg_2 = hydra.Entity("veg_2")
+ veg_2.create_entity(
+ position, ["Vegetation Layer Spawner", "Vegetation Reference Shape", "Vegetation Asset List"]
+ )
+ set_dynamic_slice_asset(veg_2, 2, os.path.join("Slices", "PurpleFlower.dynamicslice"))
+ veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id)
- # Add Vegetation Surface Mask Filter to the blender entity and add a Exclusion tag
- tag = surface_data.SurfaceTag()
- tag.SetTag(SURFACE_TAG)
- blender_entity.add_component("Vegetation Surface Mask Filter")
- pte = hydra.get_property_tree(blender_entity.components[2])
- path = "Configuration|Exclusion|Surface Tags"
- pte.add_container_item(path, 0, tag)
- blender_entity.get_set_test(2, "Configuration|Exclusion|Surface Tags|[0]", tag)
+ # Assign the vegetation areas to the Blender entity
+ pte = hydra.get_property_tree(blender_entity.components[1])
+ path = "Configuration|Vegetation Areas"
+ pte.update_container_item(path, 0, veg_1.id)
+ pte.add_container_item(path, 1, veg_2.id)
- # Toggle Inherit Behavior flag and verify vegetation instances
- self.log(
- f"Vegetation is not planted when Inherit Behavior flag is checked: {dynveg.validate_instance_count(position, 16.0, 0)}"
- )
- veg_1.get_set_test(0, "Configuration|Inherit Behavior", False)
- self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 2.0)
- self.log(
- f"Vegetation plant when Inherit Behavior flag is unchecked: {dynveg.validate_instance_count(position, 16.0, 400)}"
- )
+ # Add Vegetation Surface Mask Filter to the blender entity and add a Exclusion tag
+ tag = surface_data.SurfaceTag()
+ tag.SetTag(SURFACE_TAG)
+ blender_entity.add_component("Vegetation Surface Mask Filter")
+ pte = hydra.get_property_tree(blender_entity.components[2])
+ path = "Configuration|Exclusion|Surface Tags"
+ pte.add_container_item(path, 0, tag)
+ blender_entity.get_set_test(2, "Configuration|Exclusion|Surface Tags|[0]", tag)
+
+ # Toggle Inherit Behavior flag and verify vegetation instances
+ flag_checked_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0), 2.0)
+ Report.result(Tests.inherit_behavior_checked, flag_checked_instance_count)
+ veg_1.get_set_test(0, "Configuration|Inherit Behavior", False)
+ flag_unchecked_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 2.0)
+ Report.result(Tests.inherit_behavior_unchecked, flag_unchecked_instance_count)
-test = TestLayerSpawnerInheritBehavior()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(LayerSpawner_InheritBehaviorFlag)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py
index 8310583fe6..0da200d87a 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py
@@ -5,134 +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
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr
-import azlmbr.legacy.general as general
-import azlmbr.entity as EntityId
-import azlmbr.math as math
+def LayerSpawner_InstancesPlantInAllSupportedShapes():
+ """
+ Summary:
+ The level is loaded and vegetation area is created. Then the Vegetation Reference Shape
+ component of vegetation area is pinned with entities of different shape components to check
+ if the vegetation plants in different shaped areas.
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ Expected Behavior:
+ Vegetation properly plants in areas of any shape.
+ Test Steps:
+ 1) Open a level
+ 2) Create basic vegetation area entity and set the properties
+ 3) Box Shape Entity: create, set properties and pin to vegetation
+ 4) Capsule Shape Entity: create, set properties and pin to vegetation
+ 5) Tube Shape Entity: create, set properties and pin to vegetation
+ 6) Sphere Shape Entity: create, set properties and pin to vegetation
+ 7) Cylinder Shape Entity: create, set properties and pin to vegetation
+ 8) Prism Shape Entity: create, set properties and pin to vegetation
+ 9) Compound Shape Entity: create, set properties and pin to vegetation
-class TestLayerSpawner_AllShapesPlant(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="TestLayerSpawner_AllShapesPlant", args=["level"])
+ Note:
+ - 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:
- The level is loaded and vegetation area is created. Then the Vegetation Reference Shape
- component of vegetation area is pinned with entities of different shape components to check
- if the vegetation plants in different shaped areas.
+ :return: None
+ """
- Expected Behavior:
- Vegetation properly plants in areas of any shape.
+ import os
- Test Steps:
- 1) Create level
- 2) Create basic vegetation area entity and set the properties
- 3) Box Shape Entity: create, set properties and pin to vegetation
- 4) Capsule Shape Entity: create, set properties and pin to vegetation
- 5) Tube Shape Entity: create, set properties and pin to vegetation
- 6) Sphere Shape Entity: create, set properties and pin to vegetation
- 7) Cylinder Shape Entity: create, set properties and pin to vegetation
- 8) Prism Shape Entity: create, set properties and pin to vegetation
- 9) Compound Shape Entity: create, set properties and pin to vegetation
+ import azlmbr.legacy.general as general
+ import azlmbr.entity as EntityId
+ import azlmbr.math as math
- Note:
- - 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 largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- :return: None
- """
-
- def pin_shape_and_check_count(entity_id, count):
- hydra.get_set_test(vegetation, 2, "Configuration|Shape Entity Id", entity_id)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(vegetation.id,
- count), 2.0)
- self.test_success = self.test_success and result
-
- # 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,
+ def pin_shape_and_check_count(entity, count):
+ hydra.get_set_test(vegetation, 2, "Configuration|Shape Entity Id", entity.id)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(vegetation.id,
+ count), 2.0)
+ success = (
+ f"Found the expected number of instances in {entity.name} shape",
+ f"Unexpected number of instances found in {entity.name} shape"
)
+ Report.result(success, result)
- # 2) Create basic vegetation area entity and set the properties
- entity_position = math.Vector3(125.0, 136.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- vegetation = dynveg.create_vegetation_area("Instance Spawner",
- entity_position,
- 10.0, 10.0, 10.0,
- asset_path)
- vegetation.remove_component("Box Shape")
- vegetation.add_component("Vegetation Reference Shape")
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create surface for planting on
- dynveg.create_surface_entity("Surface Entity", entity_position, 60.0, 60.0, 1.0)
+ # 2) Create basic vegetation area entity and set the properties
+ entity_position = math.Vector3(125.0, 136.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ vegetation = dynveg.create_vegetation_area("Instance Spawner",
+ entity_position,
+ 10.0, 10.0, 10.0,
+ asset_path)
+ vegetation.remove_component("Box Shape")
+ vegetation.add_component("Vegetation Reference Shape")
- # Adjust camera to be close to the vegetation entity
- general.set_current_view_position(135.0, 102.0, 39.0)
- general.set_current_view_rotation(-15.0, 0, 0)
+ # Create surface for planting on
+ dynveg.create_surface_entity("Surface Entity", entity_position, 60.0, 60.0, 1.0)
- # 3) Box Shape Entity: create, set properties and pin to vegetation
- box = hydra.Entity("box")
- box.create_entity(math.Vector3(124.0, 126.0, 32.0), ["Box Shape"])
- new_box_dimension = math.Vector3(10.0, 10.0, 1.0)
- hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
- # This and subsequent counts are the number of "PurpleFlower" that spawn in the shape with given dimensions
- pin_shape_and_check_count(box.id, 156)
+ # Adjust camera to be close to the vegetation entity
+ general.set_current_view_position(135.0, 102.0, 39.0)
+ general.set_current_view_rotation(-15.0, 0, 0)
- # 4) Capsule Shape Entity: create, set properties and pin to vegetation
- capsule = hydra.Entity("capsule")
- capsule.create_entity(math.Vector3(120.0, 142.0, 32.0), ["Capsule Shape"])
- hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Height", 10.0)
- hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Radius", 2.0)
- pin_shape_and_check_count(capsule.id, 20)
+ # 3) Box Shape Entity: create, set properties and pin to vegetation
+ box = hydra.Entity("Box")
+ box.create_entity(math.Vector3(124.0, 126.0, 32.0), ["Box Shape"])
+ new_box_dimension = math.Vector3(10.0, 10.0, 1.0)
+ hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
+ # This and subsequent counts are the number of "PurpleFlower" that spawn in the shape with given dimensions
+ pin_shape_and_check_count(box, 156)
- # 5) Tube Shape Entity: create, set properties and pin to vegetation
- tube = hydra.Entity("tube")
- tube.create_entity(math.Vector3(124.0, 136.0, 32.0), ["Tube Shape", "Spline"])
- pin_shape_and_check_count(tube.id, 27)
+ # 4) Capsule Shape Entity: create, set properties and pin to vegetation
+ capsule = hydra.Entity("Capsule")
+ capsule.create_entity(math.Vector3(120.0, 142.0, 32.0), ["Capsule Shape"])
+ hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Height", 10.0)
+ hydra.get_set_test(capsule, 0, "Capsule Shape|Capsule Configuration|Radius", 2.0)
+ pin_shape_and_check_count(capsule, 20)
- # 6) Sphere Shape Entity: create, set properties and pin to vegetation
- sphere = hydra.Entity("sphere")
- sphere.create_entity(math.Vector3(112.0, 143.0, 32.0), ["Sphere Shape"])
- hydra.get_set_test(sphere, 0, "Sphere Shape|Sphere Configuration|Radius", 5.0)
- pin_shape_and_check_count(sphere.id, 122)
+ # 5) Tube Shape Entity: create, set properties and pin to vegetation
+ tube = hydra.Entity("Tube")
+ tube.create_entity(math.Vector3(124.0, 136.0, 32.0), ["Tube Shape", "Spline"])
+ pin_shape_and_check_count(tube, 27)
- # 7) Cylinder Shape Entity: create, set properties and pin to vegetation
- cylinder = hydra.Entity("cylinder")
- cylinder.create_entity(math.Vector3(136.0, 143.0, 32.0), ["Cylinder Shape"])
- hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
- hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
- pin_shape_and_check_count(cylinder.id, 124)
+ # 6) Sphere Shape Entity: create, set properties and pin to vegetation
+ sphere = hydra.Entity("Sphere")
+ sphere.create_entity(math.Vector3(112.0, 143.0, 32.0), ["Sphere Shape"])
+ hydra.get_set_test(sphere, 0, "Sphere Shape|Sphere Configuration|Radius", 5.0)
+ pin_shape_and_check_count(sphere, 122)
- # 8) Prism Shape Entity: create, set properties and pin to vegetation
- polygon_prism = hydra.Entity("polygonprism")
- polygon_prism.create_entity(math.Vector3(127.0, 142.0, 32.0), ["Polygon Prism Shape"])
- pin_shape_and_check_count(polygon_prism.id, 20)
+ # 7) Cylinder Shape Entity: create, set properties and pin to vegetation
+ cylinder = hydra.Entity("Cylinder")
+ cylinder.create_entity(math.Vector3(136.0, 143.0, 32.0), ["Cylinder Shape"])
+ hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
+ hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
+ pin_shape_and_check_count(cylinder, 124)
- # 9) Compound Shape Entity: create, set properties and pin to vegetation
- compound = hydra.Entity("Compound")
- compound.create_entity(math.Vector3(125.0, 136.0, 32.0), ["Compound Shape"])
- pte = hydra.get_property_tree(compound.components[0])
- shapes = [box.id, capsule.id, tube.id, sphere.id, cylinder.id, polygon_prism.id]
- for index in range(6):
- pte.add_container_item("Configuration|Child Shape Entities", index, EntityId.EntityId())
- for index, element in enumerate(shapes):
- hydra.get_set_test(compound, 0, f"Configuration|Child Shape Entities|[{index}]", element)
- pin_shape_and_check_count(compound.id, 469)
+ # 8) Prism Shape Entity: create, set properties and pin to vegetation
+ polygon_prism = hydra.Entity("Polygon Prism")
+ polygon_prism.create_entity(math.Vector3(127.0, 142.0, 32.0), ["Polygon Prism Shape"])
+ pin_shape_and_check_count(polygon_prism, 20)
+
+ # 9) Compound Shape Entity: create, set properties and pin to vegetation
+ compound = hydra.Entity("Compound")
+ compound.create_entity(math.Vector3(125.0, 136.0, 32.0), ["Compound Shape"])
+ pte = hydra.get_property_tree(compound.components[0])
+ shapes = [box.id, capsule.id, tube.id, sphere.id, cylinder.id, polygon_prism.id]
+ for index in range(6):
+ pte.add_container_item("Configuration|Child Shape Entities", index, EntityId.EntityId())
+ for index, element in enumerate(shapes):
+ hydra.get_set_test(compound, 0, f"Configuration|Child Shape Entities|[{index}]", element)
+ pin_shape_and_check_count(compound, 469)
-test = TestLayerSpawner_AllShapesPlant()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(LayerSpawner_InstancesPlantInAllSupportedShapes)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py
index f17956e066..02d30fb0f3 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py
@@ -5,115 +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
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-
-sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
-from editor_python_test_tools.editor_test_helper import EditorTestHelper
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ viewport_config_updated = (
+ "Viewport is now configured for test",
+ "Failed to configure viewport for test"
+ )
+ first_viewport_active_instance_count = (
+ "Expected number of instances found in left viewport",
+ "Unexpected number of instances found in left viewport"
+ )
+ second_viewport_inactive_instance_count = (
+ "No instances found in right viewport",
+ "Unexpectedly found instances in right viewport while not active"
+ )
+ first_viewport_inactive_instance_count = (
+ "No instances found in left viewport",
+ "Unexpectedly found instances in left viewport while not active"
+ )
+ second_viewport_active_instance_count = (
+ "Expected number of instances found in right viewport",
+ "Unexpected number of instances found in right viewport"
+ )
-class TestLayerSpawnerInstanceCameraRefresh(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="LayerSpawner_InstanceCameraRefresh", args=["level"])
+def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera():
+ """
+ Summary:
+ Test that the Dynamic Vegetation System is using the current Editor viewport camera as the center
+ of the spawn area for vegetation. To verify this, we create two separate Editor viewports pointed
+ at two different vegetation areas, and verify that as we switch between active viewports, only the
+ area directly underneath that viewport's camera has vegetation.
+ """
- def run_test(self):
- """
- Summary:
- Test that the Dynamic Vegetation System is using the current Editor viewport camera as the center
- of the spawn area for vegetation. To verify this, we create two separate Editor viewports pointed
- at two different vegetation areas, and verify that as we switch between active viewports, only the
- area directly underneath that viewport's camera has vegetation.
- """
- # Create an empty level
- self.test_success = self.create_level(
- self.args["level"],
- heightmap_resolution=128,
- heightmap_meters_per_pixel=1,
- terrain_texture_resolution=4096,
- use_terrain=False,
- )
- # Set up a test environment to validate that switching viewports correctly changes which camera
- # the vegetation system uses.
- # The test environment consists of the following:
- # - two 32 x 32 x 1 box shapes located far apart that emit a surface with no tags
- # - two 32 x 32 x 32 vegetation areas that place vegetation on the boxes
+ import os
- # Initialize some constants for our test.
- # The boxes are intentionally shifted by 0.5 meters to ensure that we get a predictable number
- # of vegetation points. By default, vegetation plants on grid corners, so if our boxes are aligned
- # with grid corner points, the right/bottom edges will include more points than we might intuitively expect.
- # By shifting by 0.5 meters, the vegetation grid points don't fall on the box edges, making the total count
- # more predictable.
- first_entity_center_point = math.Vector3(0.5, 0.5, 100.0)
- # The second box needs to be far enough away from the first that the vegetation system will never spawn instances
- # in both at the same time.
- second_entity_center_point = math.Vector3(1024.5, 1024.5, 100.0)
- box_size = 32.0
- surface_height = 1.0
- # By default, vegetation spawns 20 instances per 16 meters, so for our box of 32 meters, we should have
- # ((20 instances / 16 m) * 32 m) ^ 2 instances.
- filled_vegetation_area_instance_count = (20 * 2) * (20 * 2)
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # Change the Editor view to contain two viewports
- general.set_view_pane_layout(1)
- get_view_pane_layout_success = self.wait_for_condition(lambda: (general.get_view_pane_layout() == 1), 2)
- get_viewport_count_success = self.wait_for_condition(lambda: (general.get_viewport_count() == 2), 2)
- self.test_success = get_view_pane_layout_success and self.test_success
- self.test_success = get_viewport_count_success and self.test_success
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Set the view in the first viewport to point down at the first box
- general.set_active_viewport(0)
- self.wait_for_condition(lambda: general.get_active_viewport() == 0, 2)
- general.set_current_view_position(first_entity_center_point.x, first_entity_center_point.y,
- first_entity_center_point.z + 30.0)
- general.set_current_view_rotation(-85.0, 0.0, 0.0)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Set the view in the second viewport to point down at the second box
- general.set_active_viewport(1)
- self.wait_for_condition(lambda: general.get_active_viewport() == 1, 2)
- general.set_current_view_position(second_entity_center_point.x, second_entity_center_point.y,
- second_entity_center_point.z + 30.0)
- general.set_current_view_rotation(-85.0, 0.0, 0.0)
+ # Set up a test environment to validate that switching viewports correctly changes which camera
+ # the vegetation system uses.
+ # The test environment consists of the following:
+ # - two 32 x 32 x 1 box shapes located far apart that emit a surface with no tags
+ # - two 32 x 32 x 32 vegetation areas that place vegetation on the boxes
- # Create the "flat surface" entities to use as our vegetation surfaces
- first_surface_entity = dynveg.create_surface_entity("Surface 1", first_entity_center_point, box_size, box_size,
- surface_height)
- second_surface_entity = dynveg.create_surface_entity("Surface 2", second_entity_center_point, box_size, box_size,
- surface_height)
+ # Initialize some constants for our test.
+ # The boxes are intentionally shifted by 0.5 meters to ensure that we get a predictable number
+ # of vegetation points. By default, vegetation plants on grid corners, so if our boxes are aligned
+ # with grid corner points, the right/bottom edges will include more points than we might intuitively expect.
+ # By shifting by 0.5 meters, the vegetation grid points don't fall on the box edges, making the total count
+ # more predictable.
+ first_entity_center_point = math.Vector3(0.5, 0.5, 100.0)
+ # The second box needs to be far enough away from the first that the vegetation system will never spawn instances
+ # in both at the same time.
+ second_entity_center_point = math.Vector3(1024.5, 1024.5, 100.0)
+ box_size = 32.0
+ surface_height = 1.0
+ # By default, vegetation spawns 20 instances per 16 meters, so for our box of 32 meters, we should have
+ # ((20 instances / 16 m) * 32 m) ^ 2 instances.
+ filled_vegetation_area_instance_count = (20 * 2) * (20 * 2)
- # Create the two vegetation areas
- test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- first_veg_entity = dynveg.create_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
- box_size, test_slice_asset_path)
- second_veg_entity = dynveg.create_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size,
- box_size, test_slice_asset_path)
+ # Change the Editor view to contain two viewports
+ general.set_view_pane_layout(1)
+ get_view_pane_layout_success = helper.wait_for_condition(lambda: (general.get_view_pane_layout() == 1), 2)
+ get_viewport_count_success = helper.wait_for_condition(lambda: (general.get_viewport_count() == 2), 2)
+ Report.critical_result(Tests.viewport_config_updated, get_view_pane_layout_success and get_viewport_count_success)
- # When the first viewport is active, the first area should be full of instances, and the second should be empty
- general.set_active_viewport(0)
- viewport_0_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
- box_size / 2.0,
- filled_vegetation_area_instance_count), 5)
- self.test_success = viewport_0_success and self.test_success
- viewport_1_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
- box_size / 2.0, 0), 5)
- self.test_success = viewport_1_success and self.test_success
+ # Set the view in the first viewport to point down at the first box
+ general.set_active_viewport(0)
+ helper.wait_for_condition(lambda: general.get_active_viewport() == 0, 2)
+ general.set_current_view_position(first_entity_center_point.x, first_entity_center_point.y,
+ first_entity_center_point.z + 30.0)
+ general.set_current_view_rotation(-85.0, 0.0, 0.0)
- # When the second viewport is active, the second area should be full of instances, and the first should be empty
- general.set_active_viewport(1)
- viewport_0_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
- box_size / 2.0, 0), 5)
- self.test_success = viewport_0_success and self.test_success
- viewport_1_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
- box_size / 2.0,
- filled_vegetation_area_instance_count), 5)
- self.test_success = viewport_1_success and self.test_success
+ # Set the view in the second viewport to point down at the second box
+ general.set_active_viewport(1)
+ helper.wait_for_condition(lambda: general.get_active_viewport() == 1, 2)
+ general.set_current_view_position(second_entity_center_point.x, second_entity_center_point.y,
+ second_entity_center_point.z + 30.0)
+ general.set_current_view_rotation(-85.0, 0.0, 0.0)
+
+ # Create the "flat surface" entities to use as our vegetation surfaces
+ first_surface_entity = dynveg.create_surface_entity("Surface 1", first_entity_center_point, box_size, box_size,
+ surface_height)
+ second_surface_entity = dynveg.create_surface_entity("Surface 2", second_entity_center_point, box_size, box_size,
+ surface_height)
+
+ # Create the two vegetation areas
+ test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ first_veg_entity = dynveg.create_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size,
+ box_size, test_slice_asset_path)
+ second_veg_entity = dynveg.create_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size,
+ box_size, test_slice_asset_path)
+
+ # When the first viewport is active, the first area should be full of instances, and the second should be empty
+ general.set_active_viewport(0)
+ helper.wait_for_condition(lambda: general.get_active_viewport() == 0, 2)
+ viewport_0_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
+ box_size / 2.0,
+ filled_vegetation_area_instance_count), 5)
+ viewport_1_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
+ box_size / 2.0, 0), 5)
+ Report.result(Tests.first_viewport_active_instance_count, viewport_0_success)
+ Report.result(Tests.second_viewport_inactive_instance_count, viewport_1_success)
+
+ # When the second viewport is active, the second area should be full of instances, and the first should be empty
+ general.set_active_viewport(1)
+ helper.wait_for_condition(lambda: general.get_active_viewport() == 1, 2)
+ viewport_0_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(first_entity_center_point,
+ box_size / 2.0, 0), 5)
+ Report.result(Tests.first_viewport_inactive_instance_count, viewport_0_success)
+ viewport_1_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(second_entity_center_point,
+ box_size / 2.0,
+ filled_vegetation_area_instance_count), 5)
+ Report.result(Tests.second_viewport_active_instance_count, viewport_1_success)
-test = TestLayerSpawnerInstanceCameraRefresh()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(LayerSpawner_InstancesRefreshUsingCorrectViewportCamera)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py
index 47e9c857c2..415673c215 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py
@@ -5,92 +5,90 @@ 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
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.asset as asset
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ blocked_instance_count = (
+ "Instance count is as expected wih a Blocker setup",
+ "Found unexpected instances with a Blocker setup"
+ )
-class test_MeshBlocker_InstancesBlockedByMesh(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="MeshBlocker_InstancesBlockedByMesh", args=["level"])
+def MeshBlocker_InstancesBlockedByMesh():
+ """
+ Summary:
+ Level is created. An entity with a vegetation spawner and entity with vegetation blocker (Mesh) component are
+ added. Finally, the instance counts are checked to verify expected numbers after blocker is applied.
- def run_test(self):
- """
- Summary:
- Level is created. An entity with a vegetation spawner and entity with vegetation blocker (Mesh) component are
- added. Finally, the instance counts are checked to verify expected numbers after blocker is applied.
+ Expected Behavior:
+ The vegetation planted in the Spawner area is blocked by the Mesh of the Vegetation Blocker Mesh component.
- Expected Behavior:
- The vegetation planted in the Spawner area is blocked by the Mesh of the Vegetation Blocker Mesh component.
+ Test Steps:
+ --> Open a level
+ --> Create Spawner Entity
+ --> Create Surface Entity to spawn vegetation instances on
+ --> Create Blocker Entity with cube mesh
+ --> Verify spawned vegetation instance counts
- Test Steps:
- --> Create level
- --> Create Spawner Entity
- --> Create Surface Entity to spawn vegetation instances on
- --> Create Blocker Entity with cube mesh
- --> Verify spawned vegetation instance counts
+ Note:
+ - 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:
- - 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 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 azlmbr.asset as asset
+ import azlmbr.bus as bus
+ import azlmbr.components as components
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- general.set_current_view_position(500.49, 498.69, 46.66)
- general.set_current_view_rotation(-42.05, 0.00, -36.33)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
- entity_position,
- 10.0, 10.0, 10.0,
- asset_path)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create surface entity to plant on
- dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
+ general.set_current_view_position(500.49, 498.69, 46.66)
+ general.set_current_view_rotation(-42.05, 0.00, -36.33)
- # Create blocker entity with cube mesh
- mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
- blocker_entity = hydra.Entity("Blocker Entity")
- blocker_entity.create_entity(entity_position,
- ["Vegetation Layer Blocker (Mesh)"])
- blocker_entity.add_component_of_type(mesh_type_id)
- if blocker_entity.id.IsValid():
- print(f"'{blocker_entity.name}' created")
- cubeId = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
- False)
- blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
- components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 2.0)
+ # Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
+ entity_position,
+ 10.0, 10.0, 10.0,
+ asset_path)
- # Verify spawned instance counts are accurate after addition of Blocker Entity
- num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 2.0)
- self.test_success = self.test_success and result
+ # Create surface entity to plant on
+ dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
+
+ # Create blocker entity with cube mesh
+ mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
+ blocker_entity = hydra.Entity("Blocker Entity")
+ blocker_entity.create_entity(entity_position,
+ ["Vegetation Layer Blocker (Mesh)"])
+ blocker_entity.add_component_of_type(mesh_type_id)
+ if blocker_entity.id.IsValid():
+ print(f"'{blocker_entity.name}' created")
+ cubeId = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
+ False)
+ blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
+ components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 2.0)
+
+ # Verify spawned instance counts are accurate after addition of Blocker Entity
+ num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 2.0)
+ Report.result(Tests.blocked_instance_count, result)
-test = test_MeshBlocker_InstancesBlockedByMesh()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(MeshBlocker_InstancesBlockedByMesh)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py
index f5dad6b64d..be15c9967c 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py
@@ -5,104 +5,100 @@ 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 math as pymath
-import sys
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr
-import azlmbr.asset as asset
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.math as math
+class Tests:
+ blocked_instance_count = (
+ "Instance count is as expected wih a Blocker setup",
+ "Found unexpected instances with a Blocker setup"
+ )
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+def MeshBlocker_InstancesBlockedByMeshHeightTuning():
+ """
+ Summary:
+ A temporary level is created, then a simple vegetation area is created. A blocker area is created and it is
+ verified that the tuning of the height percent blocker setting works as expected.
+
+ Expected Behavior:
+ Vegetation is blocked only around the trunk of the tree, while it still plants under the areas covered by branches.
+
+ Test Steps:
+ 1) Open a level
+ 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ 3) Create surface entity
+ 4) Create blocker entity with sphere mesh
+ 5) Adjust the height Min/Max percentage values of blocker
+ 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
+
+ Note:
+ - 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 math as pymath
+
+ import azlmbr
+ import azlmbr.asset as asset
+ import azlmbr.bus as bus
+ import azlmbr.components as components
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+
+ general.set_current_view_position(500.49, 498.69, 46.66)
+ general.set_current_view_rotation(-42.05, 0.00, -36.33)
+
+ # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
+ entity_position,
+ 10.0, 10.0, 10.0,
+ asset_path)
+
+ # 3) Create surface entity to plant on
+ dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
+
+ # 4) Create blocker entity with rotated cube mesh
+ y_rotation = pymath.radians(45.0)
+ mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
+ blocker_entity = hydra.Entity("Blocker Entity")
+ blocker_entity.create_entity(entity_position,
+ ["Vegetation Layer Blocker (Mesh)"])
+ blocker_entity.add_component_of_type(mesh_type_id)
+ if blocker_entity.id.IsValid():
+ Report.info(f"'{blocker_entity.name}' created")
+ sphere_id = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
+ False)
+ blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
+ components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 5.0)
+ components.TransformBus(bus.Event, "SetLocalRotation", blocker_entity.id, math.Vector3(0.0, y_rotation, 0.0))
+
+ # 5) Adjust the height Max percentage values of blocker
+ blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)
+
+ # 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
+ # The number of "PurpleFlower" instances that plant on a 10 x 10 surface minus those blocked by the rotated at
+ # 80% max height factored in.
+ num_expected = 127
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.blocked_instance_count, result)
-class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="MeshBlocker_InstancesBlockedByMeshHeightTuning", args=["level"])
+if __name__ == "__main__":
- def run_test(self):
- """
- Summary:
- A temporary level is created, then a simple vegetation area is created. A blocker area is created and it is
- verified that the tuning of the height percent blocker setting works as expected.
-
- Expected Behavior:
- Vegetation is blocked only around the trunk of the tree, while it still plants under the areas covered by branches.
-
- Test Steps:
- 1) Create level
- 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- 3) Create surface entity
- 4) Create blocker entity with sphere mesh
- 5) Adjust the height Min/Max percentage values of blocker
- 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
-
- Note:
- - 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) 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,
- )
-
- general.set_current_view_position(500.49, 498.69, 46.66)
- general.set_current_view_rotation(-42.05, 0.00, -36.33)
-
- # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
- entity_position,
- 10.0, 10.0, 10.0,
- asset_path)
-
- # 3) Create surface entity to plant on
- dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0)
-
- # 4) Create blocker entity with rotated cube mesh
- y_rotation = pymath.radians(45.0)
- mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
- blocker_entity = hydra.Entity("Blocker Entity")
- blocker_entity.create_entity(entity_position,
- ["Vegetation Layer Blocker (Mesh)"])
- blocker_entity.add_component_of_type(mesh_type_id)
- if blocker_entity.id.IsValid():
- print(f"'{blocker_entity.name}' created")
- sphere_id = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
- False)
- blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
- components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 5.0)
- components.TransformBus(bus.Event, "SetLocalRotation", blocker_entity.id, math.Vector3(0.0, y_rotation, 0.0))
-
- # 5) Adjust the height Max percentage values of blocker
- blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)
-
- # 6) Verify spawned instance counts are accurate after adjusting height Max percentage of Blocker Entity
- # The number of "PurpleFlower" instances that plant on a 10 x 10 surface minus those blocked by the rotated at
- # 80% max height factored in.
- num_expected = 127
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = self.test_success and result
-
-
-test = test_MeshBlocker_InstancesBlockedByMeshHeightTuning()
-test.run()
+ from editor_python_test_tools.utils import Report
+ Report.start_test(MeshBlocker_InstancesBlockedByMeshHeightTuning)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py
index c093529888..cee8ebe5b6 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py
@@ -5,93 +5,87 @@ 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.entity as EntityId
-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:
+ new_entity_created = (
+ "Successfully created new entity",
+ "Failed to create new entity"
+ )
+ emitter_disabled_before_mesh = (
+ "Mesh Surface Tag Emitter is disabled without a Mesh component",
+ "Mesh Surface Tag Emitter is unexpectedly enabled without a Mesh component"
+ )
+ emitter_enabled_after_mesh = (
+ "Mesh Surface Tag Emitter is enabled after adding a Mesh component",
+ "Mesh Surface Tag Emitter is unexpectedly disabled after adding a Mesh component"
+ )
-class TestMeshSurfaceTagEmitter(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="MeshSurfaceTagEmitter_DependentOnMeshComponent", args=["level"])
+def MeshSurfaceTagEmitter_DependentOnMeshComponent():
+ """
+ Summary:
+ A New level is loaded. A New entity is created with component "Mesh Surface Tag Emitter". Adding a component
+ "Mesh" to the same entity.
- def run_test(self):
- """
- Summary:
- A New level is loaded. A New entity is created with component "Mesh Surface Tag Emitter". Adding a component
- "Mesh" to the same entity.
+ Expected Behavior:
+ Mesh Surface Tag Emitter is disabled until the required Mesh component is added to the entity.
- Expected Behavior:
- Mesh Surface Tag Emitter is disabled until the required Mesh component is added to the entity.
+ Test Steps:
+ 1) Open level
+ 2) Create a new entity with component "Mesh Surface Tag Emitter"
+ 3) Make sure Mesh Surface Tag Emitter is disabled
+ 4) Add Mesh to the same entity
+ 5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
- Test Steps:
- 1) Open level
- 2) Create a new entity with component "Mesh Surface Tag Emitter"
- 3) Make sure Mesh Surface Tag Emitter is disabled
- 4) Add Mesh to the same entity
- 5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
+ 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 EntityId
+ import azlmbr.math as math
- def is_component_enabled(EntityComponentIdPair):
- return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair)
+ 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 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 is_component_enabled(EntityComponentIdPair):
+ return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair)
- # 2) Create a new entity with component "Mesh Surface Tag Emitter"
- entity_position = math.Vector3(125.0, 136.0, 32.0)
- component_to_add = "Mesh Surface Tag Emitter"
- entity_id = editor.ToolsApplicationRequestBus(
- bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
- )
- meshentity = hydra.Entity("meshentity", entity_id)
- meshentity.components = []
- meshentity.components.append(hydra.add_component(component_to_add, entity_id))
- if entity_id.IsValid():
- print("New Entity Created")
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Make sure Mesh Surface Tag Emitter is disabled
- is_enabled = is_component_enabled(meshentity.components[0])
- self.test_success = self.test_success and not is_enabled
- if not is_enabled:
- print(f"{component_to_add} is Disabled")
- elif is_enabled:
- print(f"{component_to_add} is Enabled. But It should be disabled before adding Mesh")
+ # 2) Create a new entity with component "Mesh Surface Tag Emitter"
+ entity_position = math.Vector3(125.0, 136.0, 32.0)
+ component_to_add = "Mesh Surface Tag Emitter"
+ entity_id = editor.ToolsApplicationRequestBus(
+ bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
+ )
+ meshentity = hydra.Entity("meshentity", entity_id)
+ meshentity.components = []
+ meshentity.components.append(hydra.add_component(component_to_add, entity_id))
+ Report.critical_result(Tests.new_entity_created, entity_id.IsValid())
- # 4) Add Mesh to the same entity
- component = "Mesh"
- meshentity.components.append(hydra.add_component(component, entity_id))
+ # 3) Make sure Mesh Surface Tag Emitter is disabled
+ is_enabled = is_component_enabled(meshentity.components[0])
+ Report.result(Tests.emitter_disabled_before_mesh, not is_enabled)
- # 5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
- is_enabled = is_component_enabled(meshentity.components[0])
- self.test_success = self.test_success and is_enabled
- if is_enabled:
- print(f"{component_to_add} is Enabled")
- elif not is_enabled:
- print(f"{component_to_add} is Disabled. But It should be enabled after adding Mesh")
+ # 4) Add Mesh to the same entity
+ component = "Mesh"
+ meshentity.components.append(hydra.add_component(component, entity_id))
+
+ # 5) Make sure Mesh Surface Tag Emitter is enabled after adding Mesh
+ is_enabled = is_component_enabled(meshentity.components[0])
+ Report.result(Tests.emitter_enabled_after_mesh, is_enabled)
-test = TestMeshSurfaceTagEmitter()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(MeshSurfaceTagEmitter_DependentOnMeshComponent)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py
index 83beb5d0c2..d7abc66106 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py
@@ -5,75 +5,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
-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
-
-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:
+ add_surface_tag = (
+ "Surface Tag added successfully",
+ "Failed to add Surface Tag"
+ )
+ remove_surface_tag = (
+ "Successfully removed Surface Tag",
+ "Failed to remove Surface Tag"
+ )
-class TestMeshSurfaceTagEmitter(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSucessfully",
- args=["level"])
+def MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully():
+ """
+ Summary:
+ An enity with Mesh Tag Emitter and a Mesh is added to the viewport to verify if we are able to
+ add/remove surface tags.
- def run_test(self):
- """
- Summary:
- An enity with Mesh Tag Emitter and a Mesh is added to the viewport to verify if we are able to
- add/remove surface tags.
+ Expected Behavior:
+ A new Surface Tag can be added and removed from the component.
- Expected Behavior:
- A new Surface Tag can be added and removed from the component.
+ Test Steps:
+ 1) Open level
+ 2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
+ 3) Add/ remove Surface Tags
- Test Steps:
- 1) Open level
- 2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
- 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.
- 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.math as math
+ import azlmbr.surface_data as surface_data
- # 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 a new entity with components "Mesh Surface Tag Emitter", "Mesh"
- entity_position = math.Vector3(125.0, 136.0, 32.0)
- components_to_add = ["Mesh Surface Tag Emitter", "Mesh"]
- entity = hydra.Entity("entity")
- entity.create_entity(entity_position, components_to_add)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Add/ remove Surface Tags
- tag = surface_data.SurfaceTag()
- tag.SetTag("water")
- pte = hydra.get_property_tree(entity.components[0])
- path = "Configuration|Generated Tags"
- pte.add_container_item(path, 0, tag)
- success = self.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1, 5.0)
- 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, 5.0)
- self.test_success = self.test_success and success
- print(f"Removed SurfaceTag: container count is {pte.get_container_count(path).GetValue()}")
+ # 2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh"
+ entity_position = math.Vector3(125.0, 136.0, 32.0)
+ components_to_add = ["Mesh Surface Tag Emitter", "Mesh"]
+ 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|Generated Tags"
+ pte.add_container_item(path, 0, tag)
+ success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 1, 5.0)
+ Report.result(Tests.add_surface_tag, success)
+ pte.remove_container_item(path, 0)
+ success = helper.wait_for_condition(lambda: pte.get_container_count(path).GetValue() == 0, 5.0)
+ Report.result(Tests.remove_surface_tag, success)
-test = TestMeshSurfaceTagEmitter()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully)
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 361dbdaea9..b5739c2386 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
@@ -5,27 +5,30 @@ 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.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-import azlmbr.math as math
+def PhysXColliderSurfaceTagEmitter_E2E_Editor():
+ """
+ Summary:
+ Test aspects of the PhysX Collider Surface Tag Emitter Component through the BehaviorContext and the Property
+ Tree.
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ :return: None
+ """
+ import os
-class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="PhysXColliderSurfaceTagEmitter_E2E_Editor", args=["level"])
+ 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
- def validate_behavior_context(self):
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ def validate_behavior_context():
# Verify that we can create the component through the BehaviorContext
behavior_context_test_success = True
test_component = azlmbr.surface_data.SurfaceDataColliderComponent()
@@ -38,163 +41,181 @@ class TestPhysXColliderSurfaceTagEmitter(EditorTestHelper):
provider_tag2 = azlmbr.surface_data.SurfaceTag('provider_tag2')
modifier_tag1 = azlmbr.surface_data.SurfaceTag('modifier_tag1')
modifier_tag2 = azlmbr.surface_data.SurfaceTag('modifier_tag2')
- behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(test_component,
- 'providerTags',
- [provider_tag1,
- provider_tag2])
- behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(test_component,
- 'modifierTags',
- [modifier_tag1,
- modifier_tag2])
- self.log(f'SurfaceDataColliderComponent() BehaviorContext test: {behavior_context_test_success}')
+ behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(
+ test_component,
+ 'providerTags',
+ [provider_tag1,
+ provider_tag2])
+ behavior_context_test_success = behavior_context_test_success and hydra.get_set_property_test(
+ test_component,
+ 'modifierTags',
+ [modifier_tag1,
+ modifier_tag2])
+ Report.info(f'SurfaceDataColliderComponent() BehaviorContext test: {behavior_context_test_success}')
return behavior_context_test_success
- def run_test(self):
- """
- Summary:
- Test aspects of the PhysX Collider Surface Tag Emitter Component through the BehaviorContext and the Property Tree.
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- :return: None
- """
- # Create an 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,
+ # Verify all of the BehaviorContext API:
+ behavior_context = (
+ "SurfaceDataColliderComponent() Behavior Context tests were successful",
+ "SurfaceDataColliderComponent() Behavior Context tests failed"
+ )
+ Report.result(behavior_context, validate_behavior_context())
+
+ # Set up a test environment to validate the PhysX Collider Surface Tag Emitter Component.
+ # The test environment will consist of the following:
+ # - a 32 x 32 x 1 box shape that emits a surface with no tags
+ # - a 32 x 32 x 32 vegetation area that will only place vegetation on surfaces with the 'test' tag
+ # With this setup, no vegetation will appear until a Surface Tag Emitter either emits new points with
+ # the correct tag, or modifies points on our box shape to emit the correct tag.
+
+ # Initialize some arbitrary constants for our test
+ entity_center_point = math.Vector3(512.0, 512.0, 100.0)
+ invalid_tag = azlmbr.surface_data.SurfaceTag('invalid')
+ surface_tag = azlmbr.surface_data.SurfaceTag('test')
+ test_box_size = 32.0
+ baseline_surface_height = 1.0
+ collider_radius = 4.0
+ collider_diameter = collider_radius * 2.0
+
+ # Set viewport view of area under test, and toggle helpers back on
+ general.set_current_view_position(512.0, 485.0, 110.0)
+ general.set_current_view_rotation(-35.0, 0.0, 0.0)
+ general.toggle_helpers()
+
+ # Create the "flat surface" entity to use as our baseline surface
+ dynveg.create_surface_entity("Baseline Surface", entity_center_point, 32.0, 32.0, 1.0)
+
+ # Create a new entity with required vegetation area components
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path)
+
+ # Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag
+ spawner_entity.add_component("Vegetation Surface Mask Filter")
+ spawner_entity.get_set_test(3, "Configuration|Inclusion|Surface Tags", [surface_tag])
+
+ # At this point, there should be 0 instances within our entire veg area
+ initial_instance_count = (
+ "Found no instances as expected with initial setup",
+ "Unexpected found instances with initial setup"
+ )
+ initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(entity_center_point, 16.0, 0),
+ 5.0)
+ Report.result(initial_instance_count, initial_success)
+
+ # Create an entity with a PhysX Collider and our PhysX Collider Surface Tag Emitter
+ collider_entity_created = (
+ "Successfully created a Collider entity",
+ "Failed to create Collider entity"
+ )
+ collider_entity = hydra.Entity("Collider Surface")
+ collider_entity.create_entity(
+ entity_center_point,
+ ["PhysX Collider", "PhysX Collider Surface Tag Emitter"]
)
+ Report.result(collider_entity_created, collider_entity.id.IsValid())
- # Verify all of the BehaviorContext API:
- self.test_success = self.test_success and self.validate_behavior_context()
+ # Set up the PhysX Collider so that each shape type (sphere, box, capsule) has the same test height.
+ hydra.get_set_test(collider_entity, 0, "Shape Configuration|Sphere|Radius", collider_radius)
+ hydra.get_set_test(collider_entity, 0, "Shape Configuration|Box|Dimensions", math.Vector3(collider_diameter,
+ collider_diameter,
+ collider_diameter))
+ hydra.get_set_test(collider_entity, 0, "Shape Configuration|Capsule|Height", collider_diameter)
- # Set up a test environment to validate the PhysX Collider Surface Tag Emitter Component.
- # The test environment will consist of the following:
- # - a 32 x 32 x 1 box shape that emits a surface with no tags
- # - a 32 x 32 x 32 vegetation area that will only place vegetation on surfaces with the 'test' tag
- # With this setup, no vegetation will appear until a Surface Tag Emitter either emits new points with
- # the correct tag, or modifies points on our box shape to emit the correct tag.
-
- # Initialize some arbitrary constants for our test
- entity_center_point = math.Vector3(512.0, 512.0, 100.0)
- invalid_tag = azlmbr.surface_data.SurfaceTag('invalid')
- surface_tag = azlmbr.surface_data.SurfaceTag('test')
- test_box_size = 32.0
- baseline_surface_height = 1.0
- collider_radius = 4.0
- collider_diameter = collider_radius * 2.0
-
- # Set viewport view of area under test, and toggle helpers back on
- general.set_current_view_position(512.0, 485.0, 110.0)
- general.set_current_view_rotation(-35.0, 0.0, 0.0)
- general.toggle_helpers()
-
- # Create the "flat surface" entity to use as our baseline surface
- dynveg.create_surface_entity("Baseline Surface", entity_center_point, 32.0, 32.0, 1.0)
-
- # Create a new entity with required vegetation area components
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path)
-
- # Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag
- spawner_entity.add_component("Vegetation Surface Mask Filter")
- spawner_entity.get_set_test(3, "Configuration|Inclusion|Surface Tags", [surface_tag])
-
- # At this point, there should be 0 instances within our entire veg area
- initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(entity_center_point, 16.0, 0),
- 5.0)
- self.test_success = self.test_success and initial_success
-
- # 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,
- ["PhysX Collider", "PhysX Collider Surface Tag Emitter"]
- )
- if collider_entity.id.IsValid():
- self.log(f"'{collider_entity.name}' created")
-
- # Set up the PhysX Collider so that each shape type (sphere, box, capsule) has the same test height.
- hydra.get_set_test(collider_entity, 0, "Shape Configuration|Sphere|Radius", collider_radius)
- hydra.get_set_test(collider_entity, 0, "Shape Configuration|Box|Dimensions", math.Vector3(collider_diameter,
- collider_diameter,
- collider_diameter))
- hydra.get_set_test(collider_entity, 0, "Shape Configuration|Capsule|Height", collider_diameter)
-
- # Run through each collider shape type (sphere, box, capsule) and verify the surface generation
- # and surface modification of the PhysX Collision Surface Tag Emitter Component.
- for collider_shape in range(0, 3):
- hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", collider_shape)
-
- # Test: Generate a new surface on the collider.
- # There should be one instance at the very top of the collider sphere, and none on the baseline surface
- # (We use a small query box to only check for one placed instance point)
- hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [surface_tag])
- hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [invalid_tag])
- top_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
- collider_radius)
- baseline_surface_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
- (baseline_surface_height / 2.0))
- 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,
- 0.25, 0), 5.0)
- self.test_success = self.test_success and baseline_success
-
- # Test: Modify an existing surface inside the collider.
- # There should be no instances at the very top of the collider sphere, and one on the baseline surface
- # within our query box.
- # (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])
- 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,
- 0.25, 1), 5.0)
- self.test_success = self.test_success and baseline_success
-
- # Setup collider entity with a PhysX Mesh
- test_physx_mesh_asset_id = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics",
- "Material_PerFaceMaterialGetsCorrectMaterial",
- "test.pxmesh"), math.Uuid(), False)
-
- # 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(1, "Shape Configuration|Asset|Configuration|Asset Scale", asset_scale)
+ # Run through each collider shape type (sphere, box, capsule) and verify the surface generation
+ # and surface modification of the PhysX Collision Surface Tag Emitter Component.
+ for collider_shape in range(0, 3):
+ collider_shapes = {0: "Sphere", 1: "Box", 2: "Capsule"}
+ hydra.get_set_test(collider_entity, 0, "Shape Configuration|Shape", collider_shape)
# 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
+ # There should be one instance at the very top of the collider sphere, 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, 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,
- 0.25, 0), 5.0)
- self.test_success = self.test_success and baseline_success
+ on_collider_top_point_count = (
+ f"Expected number of instances found on the top point for {collider_shapes[collider_shape]} shape",
+ f"Found an unexpected number of instances on the top point for {collider_shapes[collider_shape]} shape"
+ )
+ on_collider_baseline_count = (
+ f"Expected number of instances found on the baseline point for {collider_shapes[collider_shape]} shape",
+ f"Found an unexpected number of instances on the baseline point for {collider_shapes[collider_shape]} shape"
+ )
+ hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [surface_tag])
+ hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [invalid_tag])
+ top_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
+ collider_radius)
+ baseline_surface_point = math.Vector3(entity_center_point.x, entity_center_point.y, entity_center_point.z +
+ (baseline_surface_height / 2.0))
+ top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0)
+ Report.result(on_collider_top_point_count, top_point_success)
+ baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
+ 0.25, 0), 5.0)
+ Report.result(on_collider_baseline_count, baseline_success)
# Test: Modify an existing surface inside the collider.
- # 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.
+ # There should be no instances at the very top of the collider sphere, and one on the baseline surface
+ # within our query box.
# (We use a small query box to only check for one placed instance point)
- 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,
- 0.25, 0), 5.0)
- self.test_success = self.test_success and baseline_success
+ hydra.get_set_test(collider_entity, 1, "Configuration|Generated Tags", [invalid_tag])
+ hydra.get_set_test(collider_entity, 1, "Configuration|Extended Tags", [surface_tag])
+ top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0)
+ Report.result(on_collider_top_point_count, top_point_success)
+ baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
+ 0.25, 1), 5.0)
+ Report.result(on_collider_baseline_count, baseline_success)
+
+ # Setup collider entity with a PhysX Mesh
+ test_physx_mesh_asset_id = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", os.path.join("levels", "physics",
+ "Material_PerFaceMaterialGetsCorrectMaterial",
+ "test.pxmesh"), math.Uuid(), False)
+ collider_entity.remove_component("PhysX Collider")
+ collider_entity.add_component("PhysX Collider")
+ helper.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(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)
+ Report.info("Starting PhysX Mesh Collider Test")
+ on_collider_top_point_count = (
+ f"Expected number of instances found on the top point for a PhysX Mesh",
+ f"Found an unexpected number of instances on the top point for a PhysX Mesh"
+ )
+ on_collider_baseline_count = (
+ f"Expected number of instances found on the baseline point for a PhysX Mesh",
+ f"Found an unexpected number of instances on the baseline point for a PhysX Mesh"
+ )
+ 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 = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 1), 5.0)
+ Report.result(on_collider_top_point_count, top_point_success)
+ baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
+ 0.25, 0), 5.0)
+ Report.result(on_collider_baseline_count, baseline_success)
+
+ # Test: Modify an existing surface inside the collider.
+ # 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, 0, "Configuration|Generated Tags", [invalid_tag])
+ hydra.get_set_test(collider_entity, 0, "Configuration|Extended Tags", [surface_tag])
+ top_point_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, 0.25, 0), 5.0)
+ Report.result(on_collider_top_point_count, top_point_success)
+ baseline_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(baseline_surface_point,
+ 0.25, 0), 5.0)
+ Report.result(on_collider_baseline_count, baseline_success)
-test = TestPhysXColliderSurfaceTagEmitter()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(PhysXColliderSurfaceTagEmitter_E2E_Editor)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py
index a55e88488c..5a3ee70d22 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py
@@ -5,136 +5,133 @@ 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.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_instance_count = (
+ "Initial instance count is as expected",
+ "Found an unexpected number of initial instances"
+ )
+ autosnap_enabled_instance_count = (
+ "Found the expected number of instances with Auto Snap to Surface enabled",
+ "Found an unexpected number of instances with Auto Snap to Surface enabled"
+ )
+ autosnap_disabled_instance_count = (
+ "Found the expected number of instances with Auto Snap to Surface disabled",
+ "Found an unexpected number of instances with Auto Snap to Surface disabled"
+ )
-class TestPositionModifierAutoSnapToSurface(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="PositionModifier_AutoSnapToSurface", args=["level"])
+def PositionModifier_AutoSnapToSurfaceWorks():
+ """
+ Summary:
+ Instance spawner is setup to plant on a spherical mesh. Offsets are set on the x-axis, and checks are performed
+ to ensure instances plant where expected depending on the toggle setting.
- def run_test(self):
- """
- Summary:
- Instance spawner is setup to plant on a spherical mesh. Offsets are set on the x-axis, and checks are performed
- to ensure instances plant where expected depending on the toggle setting.
+ Expected Behavior:
+ Offset instances snap to the expected surface when Auto Snap to Surface is enabled, and offset away from surface
+ when it is disabled.
- Expected Behavior:
- Offset instances snap to the expected surface when Auto Snap to Surface is enabled, and offset away from surface
- when it is disabled.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create a new entity with required vegetation area components and a Position Modifier
+ 3) Create a spherical planting surface
+ 4) Verify initial instance counts pre-filter
+ 5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
+ 6) Set the Position Modifier offset to 5 on the x-axis
+ 7) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface enabled
+ 8) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface disabled
- Test Steps:
- 1) Create a new, temporary level
- 2) Create a new entity with required vegetation area components and a Position Modifier
- 3) Create a spherical planting surface
- 4) Verify initial instance counts pre-filter
- 5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
- 6) Set the Position Modifier offset to 5 on the x-axis
- 7) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface enabled
- 8) Validate instance counts on top of and inside the sphere mesh with Auto Snap to Surface disabled
+ 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
- """
- position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
- 'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
- 'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
+ import os
- # 1) Create a new, temporary 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 azlmbr.legacy.general as general
+ import azlmbr.math as math
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components and a Position Modifier
- spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
- asset_path)
+ position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
+ 'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
+ 'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
- # Add a Vegetation Position Modifier and set offset values to 0
- spawner_entity.add_component("Vegetation Position Modifier")
- for path in position_modifier_paths:
- spawner_entity.get_set_test(3, path, 0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Create a spherical planting surface and a flat surface
- flat_entity = dynveg.create_surface_entity("Flat Surface", spawner_center_point, 32.0, 32.0, 1.0)
- hill_entity = dynveg.create_mesh_surface_entity_with_slopes("Planting Surface", spawner_center_point, 5.0)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # Disable the Flat Surface Box Shape component, and temporarily ignore initial instance counts due to LYN-2245
- editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [flat_entity.components[0]])
- """
- # 4) Verify initial instance counts pre-filter
- num_expected = 121
- spawner_success = self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and spawner_success
- """
+ # 2) Create a new entity with required vegetation area components and a Position Modifier
+ spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+ asset_path)
- # 5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
- components_to_add = ["Constant Gradient"]
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
+ # Add a Vegetation Position Modifier and set offset values to 0
+ spawner_entity.add_component("Vegetation Position Modifier")
+ for path in position_modifier_paths:
+ spawner_entity.get_set_test(3, path, 0)
- # Pin the Constant Gradient to the X axis of the spawner's Position Modifier component
- spawner_entity.get_set_test(3, 'Configuration|Position X|Gradient|Gradient Entity Id', gradient_entity.id)
+ # 3) Create a spherical planting surface
+ hill_entity = dynveg.create_mesh_surface_entity_with_slopes("Planting Surface", spawner_center_point, 5.0)
- # 6) Set the Position Modifier offset to 2.5 on the x-axis
- spawner_entity.get_set_test(3, position_modifier_paths[0], 2.5)
- spawner_entity.get_set_test(3, position_modifier_paths[1], 2.5)
+ # 4) Verify initial instance counts pre-filter
+ num_expected = 29
+ spawner_success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.initial_instance_count, spawner_success)
- # 7) Validate instance count at the top of the sphere mesh and inside the sphere mesh while Auto Snap to Surface
- # is enabled
- top_point = math.Vector3(512.0, 512.0, 37.0)
- inside_point = math.Vector3(512.0, 512.0, 35.0)
- radius = 0.5
- num_expected = 1
- self.log(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
- top_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
- 5.0)
- self.test_success = top_success and self.test_success
- num_expected = 0
- self.log(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
- inside_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
- num_expected), 5.0)
- self.test_success = inside_success and self.test_success
+ # 5) Create a child entity of the spawner entity with a Constant Gradient component and pin to spawner
+ components_to_add = ["Constant Gradient"]
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
- # 8) Toggle off Auto Snap to Surface. Instances should now plant inside the sphere and no longer on top
- spawner_entity.get_set_test(3, "Configuration|Auto Snap To Surface", False)
- num_expected = 0
- self.log(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
- top_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
- 5.0)
- self.test_success = top_success and self.test_success
- num_expected = 1
- self.log(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
- inside_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
- num_expected), 5.0)
- self.test_success = inside_success and self.test_success
+ # Pin the Constant Gradient to the X axis of the spawner's Position Modifier component
+ spawner_entity.get_set_test(3, 'Configuration|Position X|Gradient|Gradient Entity Id', gradient_entity.id)
+
+ # 6) Set the Position Modifier offset to 2.5 on the x-axis
+ spawner_entity.get_set_test(3, position_modifier_paths[0], 2.5)
+ spawner_entity.get_set_test(3, position_modifier_paths[1], 2.5)
+
+ # 7) Validate instance count at the top of the sphere mesh and inside the sphere mesh while Auto Snap to Surface
+ # is enabled
+ top_point = math.Vector3(512.0, 512.0, 37.0)
+ inside_point = math.Vector3(512.0, 512.0, 35.0)
+ radius = 0.5
+ num_expected = 1
+ Report.info(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
+ top_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
+ 5.0)
+ num_expected = 0
+ Report.info(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
+ inside_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
+ num_expected), 5.0)
+ Report.result(Tests.autosnap_enabled_instance_count, top_success and inside_success)
+
+ # 8) Toggle off Auto Snap to Surface. Instances should now plant inside the sphere and no longer on top
+ spawner_entity.get_set_test(3, "Configuration|Auto Snap To Surface", False)
+ num_expected = 0
+ Report.info(f"Checking for instances in a {radius * 2}m area at {top_point.ToString()}")
+ top_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(top_point, radius, num_expected),
+ 5.0)
+ num_expected = 1
+ Report.info(f"Checking for instances in a {radius * 2}m area at {inside_point.ToString()}")
+ inside_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(inside_point, radius,
+ num_expected), 5.0)
+ Report.result(Tests.autosnap_disabled_instance_count, top_success and inside_success)
-test = TestPositionModifierAutoSnapToSurface()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(PositionModifier_AutoSnapToSurfaceWorks)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py
index 9597f79339..c4fa91f886 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py
@@ -5,159 +5,164 @@ 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 random
-import sys
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_instance_count = (
+ "Initial instance count is as expected",
+ "Found an unexpected number of initial instances"
+ )
+ position_offset = (
+ "Found instances at all expected locations with Position Modifier offsets configured",
+ "Failed to find all expected instances at all locations with Position Modifier offsets configured"
+ )
+ position_offset_overrides = (
+ "Found instances at all expected locations with Position Modifier offset overrides configured",
+ "Failed to find all expected instances at all locations with Position Modifier offset overrides configured"
+ )
-class TestPositionModifierComponentAndOverrides(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="PositionModifierComponentAndOverrides_InstanceOffset", args=["level"])
+def PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets():
+ """
+ Summary: Range Min/Max in the Vegetation Position Modifier component and component overrides can be set for all
+ axes, and functions as expected when fed a gradient signal.
- def run_test(self):
- """
- Summary: Range Min/Max in the Vegetation Position Modifier component and component overrides can be set for all
- axes, and functions as expected when fed a gradient signal.
+ Expected Behavior: Instances are offset by the specified amount.
- Expected Behavior: Instances are offset by the specified amount.
+ Test Steps:
+ 1) Open an existing level
+ 2) Spawner area is setup with all necessary components
+ 3) Surface for planting is created
+ 4) Initial instance count validation pre-filter is performed
+ 5) An entity with a Constant Gradient of 1 is added as a child to the spawner entity, and pinned to the Position
+ Modifier Gradient Entity Id fields
+ 6) Sector size is adjusted on a Vegetation System Settings component to allow for offset instances to not fall
+ outside of the queried sector
+ 7) Random offsets are set for each axis of the Position Modifier component, and instance counts are validated
+ 8) Overrides are enabled on the Position Modifier component
+ 9) Random offsets are set for each axis of the descriptor's Position Modifier overrides, and instance counts
+ are validated
- Test Steps:
- 1) New test level is created
- 2) Spawner area is setup with all necessary components
- 3) Surface for planting is created
- 4) Initial instance count validation pre-filter is performed
- 5) An entity with a Constant Gradient of 1 is added as a child to the spawner entity, and pinned to the Position
- Modifier Gradient Entity Id fields
- 6) Sector size is adjusted on a Vegetation System Settings component to allow for offset instances to not fall
- outside of the queried sector
- 7) Random offsets are set for each axis of the Position Modifier component, and instance counts are validated
- 8) Overrides are enabled on the Position Modifier component
- 9) Random offsets are set for each axis of the descriptor's Position Modifier overrides, and instance counts
- are validated
+ 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
- """
- position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
- 'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
- 'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
+ import os
+ import random
- override_position_modifier_paths = ['Configuration|Embedded Assets|[0]|Position Modifier|Min X',
- 'Configuration|Embedded Assets|[0]|Position Modifier|Max X',
- 'Configuration|Embedded Assets|[0]|Position Modifier|Min Y',
- 'Configuration|Embedded Assets|[0]|Position Modifier|Max Y',
- 'Configuration|Embedded Assets|[0]|Position Modifier|Min Z',
- 'Configuration|Embedded Assets|[0]|Position Modifier|Max Z']
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- def generate_random_offset_list():
- offset_list = []
- while len(offset_list) < 10:
- offset = round(random.uniform(-8.0, 8.0), 2)
- if not -1.0 <= offset <= 1.0:
- offset_list.append(offset)
- print("List of values to test against = " + str(offset_list))
- return offset_list
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- def set_offset_and_verify_instance_counts(offset_to_test, center, is_override=False):
- print(f"Starting test with an offset of {offset_to_test}")
- # Set min/max values to the offset value
- if not is_override:
- for path in position_modifier_paths:
- spawner_entity.get_set_test(3, path, offset_to_test)
- else:
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Position Modifier|Override Enabled",
- True)
- for path in override_position_modifier_paths:
- spawner_entity.get_set_test(2, path, offset_to_test)
- center_point = math.Vector3(center.x + offset_to_test, center.y + offset_to_test, center.z + offset_to_test)
- radius = 0.5
- print(f"Querying for instances in a {radius * 2}m area around {center_point.ToString()}")
- offset_success = self.wait_for_condition(lambda: dynveg.validate_instance_count(center_point, radius, 1), 5.0)
- offset_success2 = self.wait_for_condition(lambda: dynveg.validate_instance_count(center, radius, 0), 5.0)
- self.test_success = offset_success and offset_success2 and self.test_success
+ position_modifier_paths = ['Configuration|Position X|Range Min', 'Configuration|Position X|Range Max',
+ 'Configuration|Position Y|Range Min', 'Configuration|Position Y|Range Max',
+ 'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max']
- # 1) Create a new, temporary 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,
- )
+ override_position_modifier_paths = ['Configuration|Embedded Assets|[0]|Position Modifier|Min X',
+ 'Configuration|Embedded Assets|[0]|Position Modifier|Max X',
+ 'Configuration|Embedded Assets|[0]|Position Modifier|Min Y',
+ 'Configuration|Embedded Assets|[0]|Position Modifier|Max Y',
+ 'Configuration|Embedded Assets|[0]|Position Modifier|Min Z',
+ 'Configuration|Embedded Assets|[0]|Position Modifier|Max Z']
- # Set view of planting area for visual debugging
- general.set_current_view_position(16.0, -5.0, 32.0)
+ def generate_random_offset_list():
+ offset_list = []
+ while len(offset_list) < 10:
+ offset = round(random.uniform(-8.0, 8.0), 2)
+ if not -1.0 <= offset <= 1.0:
+ offset_list.append(offset)
+ Report.info("List of values to test against = " + str(offset_list))
+ return offset_list
- # 2) Create a new entity with required vegetation area components
- spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path)
+ def set_offset_and_verify_instance_counts(offset_to_test, center, is_override=False):
+ Report.info(f"Starting test with an offset of {offset_to_test}")
+ # Set min/max values to the offset value
+ if not is_override:
+ for path in position_modifier_paths:
+ spawner_entity.get_set_test(3, path, offset_to_test)
+ else:
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Position Modifier|Override Enabled",
+ True)
+ for path in override_position_modifier_paths:
+ spawner_entity.get_set_test(2, path, offset_to_test)
+ center_point = math.Vector3(center.x + offset_to_test, center.y + offset_to_test, center.z + offset_to_test)
+ radius = 0.5
+ Report.info(f"Querying for instances in a {radius * 2}m area around {center_point.ToString()}")
+ offset_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(center_point, radius, 1), 5.0)
+ offset_success2 = helper.wait_for_condition(lambda: dynveg.validate_instance_count(center, radius, 0), 5.0)
+ return offset_success and offset_success2
- # Add a Vegetation Position Modifier and set offset values to 0
- spawner_entity.add_component("Vegetation Position Modifier")
- for path in position_modifier_paths:
- spawner_entity.get_set_test(3, path, 0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Add flat surface to plant on
- dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 0.0)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(16.0, -5.0, 32.0)
- # 4) Verify initial instance counts pre-filter
- num_expected = 1 # Single instance planted
- spawner_success = self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = self.test_success and spawner_success
+ # 2) Create a new entity with required vegetation area components
+ spawner_center_point = math.Vector3(16.0, 16.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path)
- # 5) Create a child entity of the spawner entity with a Constant Gradient component
- components_to_add = ["Constant Gradient"]
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
+ # Add a Vegetation Position Modifier and set offset values to 0
+ spawner_entity.add_component("Vegetation Position Modifier")
+ for path in position_modifier_paths:
+ spawner_entity.get_set_test(3, path, 0)
- # Pin the Constant Gradient to each axis of the Position Modifier
- position_modifier_gradient_paths = ['Configuration|Position X|Gradient|Gradient Entity Id',
- 'Configuration|Position Y|Gradient|Gradient Entity Id',
- 'Configuration|Position Z|Gradient|Gradient Entity Id']
- for path in position_modifier_gradient_paths:
- spawner_entity.get_set_test(3, path, gradient_entity.id)
+ # 3) Add flat surface to plant on
+ dynveg.create_surface_entity("Planting Surface", spawner_center_point, 32.0, 32.0, 0.0)
- # 6) Add a Vegetation System Settings Level component and change sector size to 32 sq meters so instances can
- # offset to a greater range and still be validated
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- "Configuration|Area System Settings|Sector Size In Meters", 32)
- sector_size = hydra.get_component_property_value(veg_system_settings_component,
- "Configuration|Area System Settings|Sector Size In Meters")
- self.test_success = (sector_size == 32) and self.test_success
+ # 4) Verify initial instance counts pre-filter
+ num_expected = 1 # Single instance planted
+ spawner_success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.initial_instance_count, spawner_success)
- # 7) Set offsets on all axes and verify instance counts
- offsets_to_test = generate_random_offset_list()
- for offset in offsets_to_test:
- if self.test_success:
- set_offset_and_verify_instance_counts(offset, spawner_center_point)
+ # 5) Create a child entity of the spawner entity with a Constant Gradient component
+ components_to_add = ["Constant Gradient"]
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(spawner_center_point, components_to_add, parent_id=spawner_entity.id)
- # 8) Toggle on allow overrides on the Position Modifier Component
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ # Pin the Constant Gradient to each axis of the Position Modifier
+ position_modifier_gradient_paths = ['Configuration|Position X|Gradient|Gradient Entity Id',
+ 'Configuration|Position Y|Gradient|Gradient Entity Id',
+ 'Configuration|Position Z|Gradient|Gradient Entity Id']
+ for path in position_modifier_gradient_paths:
+ spawner_entity.get_set_test(3, path, gradient_entity.id)
- # 9) Set offsets on all axes on descriptor overrides and verify instance counts
- for offset in offsets_to_test:
- if self.test_success:
- set_offset_and_verify_instance_counts(offset, spawner_center_point, is_override=True)
+ # 6) Add a Vegetation System Settings Level component and change sector size to 32 sq meters so instances can
+ # offset to a greater range and still be validated
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ "Configuration|Area System Settings|Sector Size In Meters", 32)
+
+ # 7) Set offsets on all axes and verify instance counts
+ offsets_to_test = generate_random_offset_list()
+ success = True
+ for offset in offsets_to_test:
+ success = success and set_offset_and_verify_instance_counts(offset, spawner_center_point)
+ Report.result(Tests.position_offset, success)
+
+ # 8) Toggle on allow overrides on the Position Modifier Component
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+
+ # 9) Set offsets on all axes on descriptor overrides and verify instance counts
+ success = True
+ for offset in offsets_to_test:
+ success = success and set_offset_and_verify_instance_counts(offset, spawner_center_point, is_override=True)
+ Report.result(Tests.position_offset_overrides, success)
-test = TestPositionModifierComponentAndOverrides()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py
index b428459032..4d8019bb33 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py
@@ -5,139 +5,138 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C4814460: A level with simple vegetation is created. A child entity with required components is then created,
-and pinned to the gradient entity id in Z direction for vegetation entity. The changes in vegetation area are observed.
-"""
-import os
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-import azlmbr.bus as bus
-import azlmbr.areasystem as areasystem
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ gradient_entity_created = (
+ "Successfully created new Gradient entity",
+ "Failed to create Gradient entity"
+ )
+ non_override_rotation_check = (
+ "Instances are rotated at expected values after initial setup",
+ "Found unexpectedly rotated instances after initial setup"
+ )
+ override_rotation_check = (
+ "Instances are rotated at expected values after configuring overrides",
+ "Found unexpectedly rotated instances after configuring overrides"
+ )
-class TestRotationModifierOverrides_InstancesRotateWithinRange(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="RotationModifierOverrides_InstancesRotateWithinRange", args=["level"])
+def RotationModifierOverrides_InstancesRotateWithinRange():
+ """
+ Summary:
+ A level with simple vegetation is created. A child entity with required components is then created,
+ and pinned to the gradient entity id in Z direction for vegetation entity. The changes in vegetation
+ area are observed.
- def run_test(self):
- """
- Summary:
- A level with simple vegetation is created. A child entity with required components is then created,
- and pinned to the gradient entity id in Z direction for vegetation entity. The changes in vegetation
- area are observed.
+ Expected Behavior:
+ Vegetation instances all rotate randomly between 0-360 degrees on the Z-axis.
- Expected Behavior:
- Vegetation instances all rotate randomly between 0-360 degrees on the Z-axis.
+ Test Steps:
+ 1) Open a new level
+ 2) Create vegetation entity and add components
+ 3) Set properties for vegetation entity
+ 4) Create new child entity
+ 5) Pin the child entity to vegetation entity as gradient entity id
+ 6) Verify rotation without per-item overrides
+ 7) Verify rotation with per-item overrides
- Test Steps:
- 1) Create level
- 2) Create vegetation entity and add components
- 3) Set properties for vegetation entity
- 4) Create new child entity
- 5) Pin the child entity to vegetation entity as gradient entity id
- 6) Verify rotation without per-item overrides
- 7) Verify rotation with per-item overrides
+ Note:
+ - 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:
- - 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
- def get_expected_rotation(min, max, gradient_value):
- return min + ((max - min) * gradient_value)
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+ import azlmbr.bus as bus
+ import azlmbr.areasystem as areasystem
- def validate_rotation(center, radius, num_expected, rot_degrees_vector):
- # Verify that every instance in the given area has the expected rotation.
- box = math.Aabb_CreateCenterRadius(center, radius)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- num_found = len(instances)
- num_validated = 0
- result = (num_found == num_expected)
- print(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
- expected_rotation = math.Quaternion()
- expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
- for instance in instances:
- is_close = instance.rotation.IsClose(expected_rotation)
- result = result and is_close
- if is_close:
- num_validated = num_validated + 1
- #else:
- # print(f'instance rotation validation: {is_close} (rotation={instance.rotation} expected={expected_rotation})')
- print(f'instance rotation validation: {result} (num_validated={num_validated})')
- return result
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 1) 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,
- )
- general.set_current_view_position(512.0, 480.0, 38.0)
+ def get_expected_rotation(min, max, gradient_value):
+ return min + ((max - min) * gradient_value)
- # 2) Create vegetation entity and add components
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path)
- spawner_entity.add_component("Vegetation Rotation Modifier")
- # Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
- num_expected = 20 * 20
- # This is technically twice as big as we need, but we want to make sure our query radius is large enough to discover every
- # instance we've created.
- area_radius = 16.0
+ def validate_rotation(center, radius, num_expected, rot_degrees_vector):
+ # Verify that every instance in the given area has the expected rotation.
+ box = math.Aabb_CreateCenterRadius(center, radius)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ num_found = len(instances)
+ num_validated = 0
+ result = (num_found == num_expected)
+ Report.info(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
+ expected_rotation = math.Quaternion()
+ expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
+ for instance in instances:
+ is_close = instance.rotation.IsClose(expected_rotation)
+ result = result and is_close
+ if is_close:
+ num_validated = num_validated + 1
+ Report.info(f'instance rotation validation: {result} (num_validated={num_validated})')
+ return result
- # Create surface to spawn on
- dynveg.create_surface_entity("Surface Entity", entity_position, 16.0, 16.0, 1.0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # 3) Set properties for the rotation override on the descriptor, but don't set "allow overrides" on the rotation modifier yet.
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Override Enabled", True)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Min Z", -70.0)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Max Z", 30.0)
+ # 2) Create vegetation entity and add components
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path)
+ spawner_entity.add_component("Vegetation Rotation Modifier")
+ # Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances.
+ num_expected = 20 * 20
+ # This is technically twice as big as we need, but we want to make sure our query radius is large enough to discover
+ # every instance we've created.
+ area_radius = 16.0
- # 4) Create new child entity with a constant gradient
- constant_gradient_value = 0.25
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(
- entity_position,
- ["Constant Gradient"],
- parent_id=spawner_entity.id
- )
- if gradient_entity.id.IsValid():
- self.log(f"'{gradient_entity.name}' created")
- gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
+ # Create surface to spawn on
+ dynveg.create_surface_entity("Surface Entity", entity_position, 16.0, 16.0, 1.0)
- # 5) Pin the child entity to vegetation entity as gradient entity id
- spawner_entity.get_set_test(3, "Configuration|Rotation Z|Gradient|Gradient Entity Id", gradient_entity.id)
+ # 3) Set properties for the rotation override on the descriptor, but don't set "allow overrides" on the rotation
+ # modifier yet
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Override Enabled", True)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Min Z", -70.0)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Rotation Modifier|Max Z", 30.0)
- # 6) Verify that without per-item overrides, the rotation matches the one calculated from the default rotation range.
- general.idle_wait(1.0)
- rotation_degrees = get_expected_rotation(-180.0, 180.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
- 5.0)
- self.test_success = self.test_success and rotation_success
+ # 4) Create new child entity with a constant gradient
+ constant_gradient_value = 0.25
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(
+ entity_position,
+ ["Constant Gradient"],
+ parent_id=spawner_entity.id
+ )
+ Report.critical_result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
+ gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
- # 7) Verify that with per-item overrides enabled, the rotation matches the one calculated from the override range.
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
- rotation_degrees = get_expected_rotation(-70.0, 30.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
- 5.0)
- self.test_success = self.test_success and rotation_success
+ # 5) Pin the child entity to vegetation entity as gradient entity id
+ spawner_entity.get_set_test(3, "Configuration|Rotation Z|Gradient|Gradient Entity Id", gradient_entity.id)
+
+ # 6) Verify that without per-item overrides, the rotation matches the one calculated from the default rotation range
+ general.idle_wait(1.0)
+ rotation_degrees = get_expected_rotation(-180.0, 180.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
+ 5.0)
+ Report.result(Tests.non_override_rotation_check, rotation_success)
+
+ # 7) Verify that with per-item overrides enabled, the rotation matches the one calculated from the override range.
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ rotation_degrees = get_expected_rotation(-70.0, 30.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(entity_position, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
+ 5.0)
+ Report.result(Tests.override_rotation_check, rotation_success)
-test = TestRotationModifierOverrides_InstancesRotateWithinRange()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(RotationModifierOverrides_InstancesRotateWithinRange)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py
index 6b6f66467b..c261415958 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py
@@ -5,207 +5,226 @@ 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.legacy.general as general
-import azlmbr.bus as bus
-import azlmbr.areasystem as areasystem
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ gradient_entity_created = (
+ "Successfully created new Gradient entity",
+ "Failed to create Gradient entity"
+ )
+ rotation_baseline = (
+ "Instances are not rotated after initial setup",
+ "Unexpectedly found rotated instances after initial setup"
+ )
+ x_axis_rotation_180 = (
+ "Instances rotated 180 degrees on X-axis as expected",
+ "Found unexpected instance rotation on X-axis"
+ )
+ x_axis_rotation_90 = (
+ "Instances rotated 90 degrees on X-axis as expected",
+ "Found unexpected instance rotation on X-axis"
+ )
+ y_axis_rotation_180 = (
+ "Instances rotated 180 degrees on Y-axis as expected",
+ "Found unexpected instance rotation on Y-axis"
+ )
+ y_axis_rotation_90 = (
+ "Instances rotated 90 degrees on Y-axis as expected",
+ "Found unexpected instance rotation on Y-axis"
+ )
+ z_axis_rotation_180 = (
+ "Instances rotated 180 degrees on Z-axis as expected",
+ "Found unexpected instance rotation on Z-axis"
+ )
+ z_axis_rotation_90 = (
+ "Instances rotated 90 degrees on Z-axis as expected",
+ "Found unexpected instance rotation on Z-axis"
+ )
-class TestRotationModifier_InstancesRotateWithinRange(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="RotationModifier_InstancesRotateWithinRange", args=["level"])
+def RotationModifier_InstancesRotateWithinRange():
+ """
+ Summary: Range Min/Max in the Vegetation Rotation Modifier component can be set for all axes,
+ and functions as expected when fed a gradient signal
- def run_test(self):
- """
- Summary: Range Min/Max in the Vegetation Rotation Modifier component can be set for all axes,
- and functions as expected when fed a gradient signal
-
- Vegetation Entity: Set in the middle of the level it holds a child entity and the following components:
- Vegetation Asset List
- Box Shape (size: <10, 10, 10>)
- Vegetation Layer Spawner
- Vegetation Rotation Modifier
- Rotation X (gradient: child, Range Min: Variable, Range Max: Variable)
- Rotation Y (gradient: child, Range Min: Variable, Range Max: Variable)
- Rotation Z (gradient: child, Range Min: Variable, Range Max: Variable)
+ Vegetation Entity: Set in the middle of the level it holds a child entity and the following components:
+ Vegetation Asset List
+ Box Shape (size: <10, 10, 10>)
+ Vegetation Layer Spawner
+ Vegetation Rotation Modifier
+ Rotation X (gradient: child, Range Min: Variable, Range Max: Variable)
+ Rotation Y (gradient: child, Range Min: Variable, Range Max: Variable)
+ Rotation Z (gradient: child, Range Min: Variable, Range Max: Variable)
- Child Entity: Child to Vegetation Entity has the following components:
- Box Shape (size: <10, 10, 10>)
- Gradient Transform Modifier
- Constant Gradient
+ Child Entity: Child to Vegetation Entity has the following components:
+ Box Shape (size: <10, 10, 10>)
+ Gradient Transform Modifier
+ Constant Gradient
- Expected Behavior: The vegetation area adjusts rotation based on the Constant Gradient component
- and the min and max values for each component. Min max of each axis is checked
+ Expected Behavior: The vegetation area adjusts rotation based on the Constant Gradient component
+ and the min and max values for each component. Min max of each axis is checked
- Test Steps:
- 1) Create level
- 2) Set up vegetation entities
- 3) X-axis Check
- 4) Y-axis Check
- 5) Z-axis Check
+ Test Steps:
+ 1) Open a new level
+ 2) Set up vegetation entities
+ 3) X-axis Check
+ 4) Y-axis Check
+ 5) Z-axis Check
- Note:
- - 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:
+ - 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
+ """
- # Test Constants
- LEVEL_CENTER = math.Vector3(512.0, 512.0, 32.0)
- constant_gradient_value = 0.15
+ import os
- # Helper Functions
- def change_range_max(axis, value):
- spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Max", value)
+ import azlmbr.math as math
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.areasystem as areasystem
- def change_range_min(axis, value):
- spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Min", value)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- def get_expected_rotation(min, max, gradient_value):
- return min + ((max - min) * gradient_value)
+ # Test Constants
+ LEVEL_CENTER = math.Vector3(512.0, 512.0, 32.0)
+ constant_gradient_value = 0.15
- def validate_rotation(center, radius, num_expected, rot_degrees_vector):
- # Verify that every instance in the given area has the expected rotation.
- box = math.Aabb_CreateCenterRadius(center, radius)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- num_found = len(instances)
- result = (num_found == num_expected)
- print(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
- expected_rotation = math.Quaternion()
- expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
- for instance in instances:
- result = result and instance.rotation.IsClose(expected_rotation)
- print(f'instance rotation validation: {result} (rotation={instance.rotation} expected={expected_rotation})')
- return result
+ # Helper Functions
+ def change_range_max(axis, value):
+ spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Max", value)
+ def change_range_min(axis, value):
+ spawner_entity.get_set_test(3, f"Configuration|Rotation {axis}|Range Min", value)
- # Main Script
- # 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,
+ def get_expected_rotation(min, max, gradient_value):
+ return min + ((max - min) * gradient_value)
+
+ def validate_rotation(center, radius, num_expected, rot_degrees_vector):
+ # Verify that every instance in the given area has the expected rotation.
+ box = math.Aabb_CreateCenterRadius(center, radius)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ num_found = len(instances)
+ result = (num_found == num_expected)
+ Report.info(f'instance count validation: {result} (found={num_found}, expected={num_expected})')
+ expected_rotation = math.Quaternion()
+ expected_rotation.SetFromEulerDegrees(rot_degrees_vector)
+ for instance in instances:
+ result = result and instance.rotation.IsClose(expected_rotation)
+ Report.info(f'instance rotation validation: {result} (rotation={instance.rotation} expected={expected_rotation})')
+ return result
+
+ # Main Script
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+ general.set_current_view_position(512.0, 480.0, 38.0)
+
+ # 2) Set up vegetation entities
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path)
+
+ additional_components = [
+ "Vegetation Rotation Modifier"
+ ]
+ for component in additional_components:
+ spawner_entity.add_component(component)
+
+ # Create surface to spawn vegetation on
+ dynveg.create_surface_entity("Surface Entity", LEVEL_CENTER, 10.0, 10.0, 1.0)
+
+ # Create Gradient Entity
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(
+ LEVEL_CENTER,
+ ["Constant Gradient"],
+ parent_id=spawner_entity.id
+ )
+ Report.critical_result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
+ gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
+
+ # Vegetation Rotation Modifier
+ for axis in ["X", "Y", "Z"]:
+ spawner_entity.get_set_test(
+ 3, f"Configuration|Rotation {axis}|Gradient|Gradient Entity Id", gradient_entity.id
)
- general.set_current_view_position(512.0, 480.0, 38.0)
- # 2) Set up vegetation entities
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path)
+ # Set up constants used across all the rotation checks
- additional_components = [
- "Vegetation Rotation Modifier"
- ]
- for component in additional_components:
- spawner_entity.add_component(component)
+ # Choose an area large enough to contain all of the instances we spawned.
+ area_center = LEVEL_CENTER
+ area_radius = 20.0
+ # We're spawning a 2x2 area, which will have 3 rows of 3 instances due to default vegetation system spacing, so
+ # we should have a total of 9 instances.
+ num_expected = 9
- # Create surface to spawn vegetation on
- dynveg.create_surface_entity("Surface Entity", LEVEL_CENTER, 10.0, 10.0, 1.0)
+ # 3) X-axis check
+ # baseline, verify that we initially have no rotation
+ change_range_min("Z", 0.0)
+ change_range_max("Z", 0.0)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, 0.0)), 5.0)
+ Report.result(Tests.rotation_baseline, rotation_success)
- # Create Gradient Entity
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(
- LEVEL_CENTER,
- ["Constant Gradient"],
- parent_id=spawner_entity.id
- )
- if gradient_entity.id.IsValid():
- self.log(f"'{gradient_entity.name}' created")
- gradient_entity.get_set_test(0, "Configuration|Value", constant_gradient_value)
+ # Adjust x-axis range min / max to (-180, 0).
+ # Because we have a constant gradient of 0.25, our actual rotation should be (min + (max - min) * gradient),
+ # or (-180 + (0 - -180) * 0.25)
+ change_range_min("X", -180.0)
+ rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
+ 5.0)
+ Report.result(Tests.x_axis_rotation_180, rotation_success)
- # Vegetation Rotation Modifier
- for axis in ["X", "Y", "Z"]:
- spawner_entity.get_set_test(
- 3, f"Configuration|Rotation {axis}|Gradient|Gradient Entity Id", gradient_entity.id
- )
+ # Set the min / max to (0, 90), with an expected result of (0 + (90 - 0) * 0.25)
+ change_range_min("X", 0.0)
+ change_range_max("X", 90.0)
+ rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
+ 5.0)
+ Report.result(Tests.x_axis_rotation_90, rotation_success)
+ change_range_max("X", 0.0)
- # Set up constants used across all the rotation checks
+ # 4) Y-axis check
+ change_range_min("Y", -180.0)
+ rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
+ 5.0)
+ Report.result(Tests.y_axis_rotation_180, rotation_success)
- # Choose an area large enough to contain all of the instances we spawned.
- area_center = LEVEL_CENTER
- area_radius = 20.0
- # We're spawning a 2x2 area, which will have 3 rows of 3 instances due to default vegetation system spacing, so
- # we should have a total of 9 instances.
- num_expected = 9
-
- # 3) X-axis check
- general.idle_wait(3.0) # Allow mesh to load
+ change_range_min("Y", 0.0)
+ change_range_max("Y", 90.0)
+ rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
+ 5.0)
+ Report.result(Tests.y_axis_rotation_90, rotation_success)
+ change_range_max("Y", 0.0)
- # baseline, verify that we initially have no rotation
- change_range_min("Z", 0.0)
- change_range_max("Z", 0.0)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, 0.0)),
- 5.0)
- self.test_success = self.test_success and rotation_success
+ # 5) Z-axis check
+ change_range_min("Z", -180.0)
+ rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
+ 5.0)
+ Report.result(Tests.z_axis_rotation_180, rotation_success)
- # Adjust x-axis range min / max to (-180, 0).
- # Because we have a constant gradient of 0.25, our actual rotation should be (min + (max - min) * gradient),
- # or (-180 + (0 - -180) * 0.25)
- change_range_min("X", -180.0)
- rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
- 5.0)
- self.test_success = self.test_success and rotation_success
-
- # Set the min / max to (0, 90), with an expected result of (0 + (90 - 0) * 0.25)
- change_range_min("X", 0.0)
- change_range_max("X", 90.0)
- rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(rotation_degrees, 0.0, 0.0)),
- 5.0)
- self.test_success = self.test_success and rotation_success
-
- change_range_max("X", 0.0)
-
- # 4) Y-axis check
- change_range_min("Y", -180.0)
- rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
- 5.0)
- self.test_success = self.test_success and rotation_success
-
- change_range_min("Y", 0.0)
- change_range_max("Y", 90.0)
- rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, rotation_degrees, 0.0)),
- 5.0)
- self.test_success = self.test_success and rotation_success
-
- change_range_max("Y", 0.0)
-
- # 5) Z-axis check
- change_range_min("Z", -180.0)
- rotation_degrees = get_expected_rotation(-180.0, 0.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
- 5.0)
- self.test_success = self.test_success and rotation_success
-
- change_range_min("Z", 0.0)
- change_range_max("Z", 90.0)
- rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
- rotation_success = self.wait_for_condition(
- lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
- 5.0)
- self.test_success = self.test_success and rotation_success
+ change_range_min("Z", 0.0)
+ change_range_max("Z", 90.0)
+ rotation_degrees = get_expected_rotation(0.0, 90.0, constant_gradient_value)
+ rotation_success = helper.wait_for_condition(
+ lambda: validate_rotation(area_center, area_radius, num_expected, math.Vector3(0.0, 0.0, rotation_degrees)),
+ 5.0)
+ Report.result(Tests.z_axis_rotation_90, rotation_success)
-test = TestRotationModifier_InstancesRotateWithinRange()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(RotationModifier_InstancesRotateWithinRange)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py
index d065c821bf..9f2359ebe2 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py
@@ -5,153 +5,155 @@ 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.areasystem as areasystem
-import azlmbr.bus as bus
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
-
-# Constants
-CLOSE_ENOUGH_THRESHOLD = 0.01
+class Tests:
+ gradient_entity_created = (
+ "Successfully created Gradient entity",
+ "Failed to create Gradient entity"
+ )
+ scale_values_set = (
+ "Scale Min and Scale Max are set to 0.1 and 1.0 in Vegetation Asset List",
+ "Scale Min and Scale Max are not set to 0.1 and 1.0 in Vegetation Asset List"
+ )
+ instance_count = (
+ "Found the expected number of instances",
+ "Found an unexpected number of instances"
+ )
+ instances_properly_scaled = (
+ "All instances scaled within appropriate range",
+ "Found instances scaled outside of the appropriate range"
+ )
-class TestScaleModifierOverrides_InstancesProperlyScale(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="ScaleModifierOverrides_InstancesProperlyScale", args=["level"])
+def ScaleModifierOverrides_InstancesProperlyScale():
+ """
+ Summary:
+ A level is created, then as simple vegetation area is created. Vegetation Scale Modifier component is
+ added to the vegetation area. A new child entity is created with Random Noise Gradient Generator,
+ Gradient Transform Modifier, and Box Shape. Child entity is set as gradient entity id in Vegetation
+ Scale Modifier, and scale of instances is validated to fall within expected range.
- def run_test(self):
- """
- Summary:
- A level is created, then as simple vegetation area is created. Vegetation Scale Modifier component is
- added to the vegetation area. A new child entity is created with Random Noise Gradient Generator,
- Gradient Transform Modifier, and Box Shape. Child entity is set as gradient entity id in Vegetation
- Scale Modifier, and scale of instances is validated to fall within expected range.
+ Expected Behavior:
+ Vegetation instances have random scale between Range Min and Range Max applied.
- Expected Behavior:
- Vegetation instances have random scale between Range Min and Range Max applied.
+ Test Steps:
+ 1) Open an existing level
+ 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ 3) Set a valid mesh asset on the Vegetation Asset List
+ 4) Add Vegetation Scale Modifier component to the vegetation and set the values
+ 5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
+ 6) Create a new child entity and add components
+ 7) Add child entity as gradient entity id in Vegetation Scale Modifier
+ 8) Validate scale of instances with a few different min/max override values
- Test Steps:
- 1) Create level
- 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- 3) Set a valid mesh asset on the Vegetation Asset List
- 4) Add Vegetation Scale Modifier component to the vegetation and set the values
- 5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
- 6) Create a new child entity and add components
- 7) Add child entity as gradient entity id in Vegetation Scale Modifier
- 8) Validate scale of instances with a few different min/max override values
+ Note:
+ - 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:
- - 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
- def set_and_validate_scale(entity, min_scale, max_scale):
- # Set Range Min/Max
- entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Min", min_scale)
- entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Max", max_scale)
+ import azlmbr.areasystem as areasystem
+ import azlmbr.bus as bus
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # Clear all areas to force a refresh
- general.run_console('veg_debugClearAllAreas')
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Wait for instances to spawn
- num_expected = 20 * 20
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ # Constants
+ CLOSE_ENOUGH_THRESHOLD = 0.01
- # Validate scale values of instances
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- if len(instances) == num_expected:
- for instance in instances:
- if min_scale <= instance.scale <= max_scale:
- self.log("All instances scaled within appropriate range")
- return True
- self.log(f"Instance at {instance.position} scale is {instance.scale}. Expected between "
- f"{min_scale}/{max_scale}")
- return False
- self.log(f"Failed to find all instances! Found {len(instances)}, expected {num_expected}.")
- return False
+ def set_and_validate_scale(entity, min_scale, max_scale):
+ # Set Range Min/Max
+ entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Min", min_scale)
+ entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Max", max_scale)
- # 1) Create level and set an appropriate view of spawner area
- self.test_success = self.create_level(
- self.args["level"],
- heightmap_resolution=1024,
- heightmap_meters_per_pixel=1,
- terrain_texture_resolution=4096,
- use_terrain=False,
+ # Refresh the planted instances
+ general.run_console("veg_DebugClearAllAreas")
+
+ # Check the initial instance count
+ num_expected = 20 * 20
+ success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, success)
+
+ # Validate scale values of instances
+ box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ for instance in instances:
+ if min_scale <= instance.scale <= max_scale:
+ return True
+ return False
+
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+
+ general.set_current_view_position(500.49, 498.69, 46.66)
+ general.set_current_view_rotation(-42.05, 0.00, -36.33)
+
+ # 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path)
+
+ # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
+ dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
+ hydra.add_level_component("Vegetation Debugger")
+
+ # 4) Add Vegetation Scale Modifier component to the vegetation and set the values
+ spawner_entity.add_component("Vegetation Scale Modifier")
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+
+ # 5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Override Enabled", True)
+ scale_min = float(
+ format(
+ (
+ hydra.get_component_property_value(
+ spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Min"
+ )
+ ),
+ ".1f",
)
-
- general.set_current_view_position(500.49, 498.69, 46.66)
- general.set_current_view_rotation(-42.05, 0.00, -36.33)
-
- # 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path)
-
- # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
- dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
- hydra.add_level_component("Vegetation Debugger")
-
- # 4) Add Vegetation Scale Modifier component to the vegetation and set the values
- spawner_entity.add_component("Vegetation Scale Modifier")
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
-
- # 5) Toggle on Scale Modifier Override and verify Scale Min and Scale Max are set 0.1 and 1.0
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Scale Modifier|Override Enabled", True)
- scale_min = float(
- format(
- (
- hydra.get_component_property_value(
- spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Min"
- )
- ),
- ".1f",
- )
+ )
+ scale_max = float(
+ format(
+ (
+ hydra.get_component_property_value(
+ spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Max"
+ )
+ ),
+ ".1f",
)
- scale_max = float(
- format(
- (
- hydra.get_component_property_value(
- spawner_entity.components[2], "Configuration|Embedded Assets|[0]|Scale Modifier|Max"
- )
- ),
- ".1f",
- )
- )
- if ((scale_max - 1.0) < CLOSE_ENOUGH_THRESHOLD) and ((scale_min - 0.1) < CLOSE_ENOUGH_THRESHOLD):
- self.log("Scale Min and Scale Max are set to 0.1 and 1.0 in Vegetation Asset List")
- else:
- self.log("Scale Min and Scale Max are not set to 0.1 and 1.0 in Vegetation Asset List")
+ )
+ Report.result(Tests.scale_values_set, ((scale_max - 1.0) < CLOSE_ENOUGH_THRESHOLD) and
+ ((scale_min - 0.1) < CLOSE_ENOUGH_THRESHOLD))
- # 6) Create a new child entity and add components
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(
- entity_position,
- ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
- parent_id=spawner_entity.id
- )
- if gradient_entity.id.IsValid():
- self.log(f"'{gradient_entity.name}' created")
+ # 6) Create a new child entity and add components
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(
+ entity_position,
+ ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
+ parent_id=spawner_entity.id
+ )
+ Report.result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
- # 7) Add child entity as gradient entity id in Vegetation Scale Modifier
- spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
+ # 7) Add child entity as gradient entity id in Vegetation Scale Modifier
+ spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
- # 8) Validate instances are scaled properly via a few different Range Min/Max settings on the override
- self.test_success = set_and_validate_scale(spawner_entity, 0.1, 1.0) and self.test_success
- self.test_success = set_and_validate_scale(spawner_entity, 2.0, 2.5) and self.test_success
- self.test_success = set_and_validate_scale(spawner_entity, 1.0, 5.0) and self.test_success
+ # 8) Validate instances are scaled properly via a few different Range Min/Max settings on the override
+ Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 0.1, 1.0))
+ Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 2.0, 2.5))
+ Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 1.0, 5.0))
-test = TestScaleModifierOverrides_InstancesProperlyScale()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(ScaleModifierOverrides_InstancesProperlyScale)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py
index e579495e42..b2fadaa703 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py
@@ -5,123 +5,123 @@ 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.areasystem as areasystem
-import azlmbr.bus as bus
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ gradient_entity_created = (
+ "Successfully created Gradient entity",
+ "Failed to create Gradient entity"
+ )
+ instance_count = (
+ "Found the expected number of instances",
+ "Found an unexpected number of instances"
+ )
+ instances_properly_scaled = (
+ "All instances scaled within appropriate range",
+ "Found instances scaled outside of the appropriate range"
+ )
-class TestScaleModifier_InstancesProperlyScale(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="ScaleModifier_InstancesProperlyScale", args=["level"])
+def ScaleModifier_InstancesProperlyScale():
+ """
+ Summary:
+ A New level is created. A New entity is created with components Vegetation Layer Spawner, Vegetation Asset List,
+ Box Shape and Vegetation Scale Modifier. A New child entity is created with components Random Noise Gradient,
+ Gradient Transform Modifier, and Box Shape. Pin the Random Noise entity to the Gradient Entity Id field for
+ the Gradient group. Range Min and Range Max are set to few values and values are validated. Range Min and Range
+ Max are set to few other values and values are validated.
- def run_test(self):
- """
- Summary:
- A New level is created. A New entity is created with components Vegetation Layer Spawner, Vegetation Asset List,
- Box Shape and Vegetation Scale Modifier. A New child entity is created with components Random Noise Gradient,
- Gradient Transform Modifier, and Box Shape. Pin the Random Noise entity to the Gradient Entity Id field for
- the Gradient group. Range Min and Range Max are set to few values and values are validated. Range Min and Range
- Max are set to few other values and values are validated.
+ Expected Behavior:
+ Vegetation instances are scaled within Range Min/Range Max.
- Expected Behavior:
- Vegetation instances are scaled within Range Min/Range Max.
+ Test Steps:
+ 1) Open an existing level
+ 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
+ Vegetation Scale Modifier
+ 3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
+ 4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
+ 5) Range Min/Max is set to few different values on the Vegetation Scale Modifier component and
+ scale of instances is validated
- Test Steps:
- 1) Create level
- 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
- Vegetation Scale Modifier
- 3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
- 4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
- 5) Range Min/Max is set to few different values on the Vegetation Scale Modifier component and
- scale of instances is validated
+ Note:
+ - 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:
- - 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
- def set_and_validate_scale(entity, min_scale, max_scale):
- # Set Range Min/Max
- entity.get_set_test(3, "Configuration|Range Min", min_scale)
- entity.get_set_test(3, "Configuration|Range Max", max_scale)
+ import azlmbr.areasystem as areasystem
+ import azlmbr.bus as bus
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # Clear all areas to force a refresh
- general.run_console('veg_debugClearAllAreas')
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Wait for instances to spawn
- num_expected = 20 * 20
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ def set_and_validate_scale(entity, min_scale, max_scale):
+ # Set Range Min/Max
+ entity.get_set_test(3, "Configuration|Range Min", min_scale)
+ entity.get_set_test(3, "Configuration|Range Max", max_scale)
- # Validate scale values of instances
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- if len(instances) == num_expected:
- for instance in instances:
- if min_scale <= instance.scale <= max_scale:
- self.log("All instances scaled within appropriate range")
- return True
- self.log(f"Instance at {instance.position} scale is {instance.scale}. Expected between "
- f"{min_scale}/{max_scale}")
- return False
- self.log(f"Failed to find all instances! Found {len(instances)}, expected {num_expected}.")
- return False
+ # Refresh the planted instances
+ general.run_console("veg_DebugClearAllAreas")
- # 1) Create level and set an appropriate view of spawner area
- self.test_success = self.create_level(
- self.args["level"],
- heightmap_resolution=1024,
- heightmap_meters_per_pixel=1,
- terrain_texture_resolution=4096,
- use_terrain=False,
- )
+ # Check the initial instance count
+ num_expected = 20 * 20
+ success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, success)
- general.set_current_view_position(500.49, 498.69, 46.66)
- general.set_current_view_rotation(-42.05, 0.00, -36.33)
+ # Validate scale values of instances
+ box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', entity.id)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ for instance in instances:
+ if min_scale <= instance.scale <= max_scale:
+ return True
+ return False
- # 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
- # Vegetation Scale Modifier
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0,
- asset_path)
- spawner_entity.add_component("Vegetation Scale Modifier")
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
- dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
- hydra.add_level_component("Vegetation Debugger")
+ general.set_current_view_position(500.49, 498.69, 46.66)
+ general.set_current_view_rotation(-42.05, 0.00, -36.33)
- # 3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
- gradient_entity = hydra.Entity("Gradient Entity")
- gradient_entity.create_entity(
- entity_position,
- ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
- parent_id=spawner_entity.id
- )
- if gradient_entity.id.IsValid():
- self.log(f"'{gradient_entity.name}' created")
+ # 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and
+ # Vegetation Scale Modifier
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0,
+ asset_path)
+ spawner_entity.add_component("Vegetation Scale Modifier")
- # 4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
- spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
+ # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes
+ dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0)
+ hydra.add_level_component("Vegetation Debugger")
- # 5) Set Range Min/Max on the Vegetation Scale Modifier component to diff values, and verify instance scale is
- # within bounds
- self.test_success = set_and_validate_scale(spawner_entity, 2.0, 4.0) and self.test_success
- self.test_success = set_and_validate_scale(spawner_entity, 12.0, 40.0) and self.test_success
- self.test_success = set_and_validate_scale(spawner_entity, 0.5, 2.5) and self.test_success
+ # 3) Create child entity with components Random Noise Gradient, Gradient Transform Modifier and Box Shape
+ gradient_entity = hydra.Entity("Gradient Entity")
+ gradient_entity.create_entity(
+ entity_position,
+ ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"],
+ parent_id=spawner_entity.id
+ )
+ Report.critical_result(Tests.gradient_entity_created, gradient_entity.id.IsValid())
+
+ # 4) Pin the Random Noise entity to the Gradient Entity Id field for the Gradient group.
+ spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", gradient_entity.id)
+
+ # 5) Set Range Min/Max on the Vegetation Scale Modifier component to diff values, and verify instance scale is
+ # within bounds
+ Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 2.0, 4.0))
+ Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 12.0, 40.0))
+ Report.result(Tests.instances_properly_scaled, set_and_validate_scale(spawner_entity, 0.5, 2.5))
-test = TestScaleModifier_InstancesProperlyScale()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(ScaleModifier_InstancesProperlyScale)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py
new file mode 100644
index 0000000000..1b9c6aa5ea
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py
@@ -0,0 +1,113 @@
+"""
+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:
+ instance_count_in_box_shape = (
+ "Only found instances in the configured Box Shape intersection area",
+ "Found instances outside of the configured Box Shape intersection area"
+ )
+ instance_count_in_cylinder_shape = (
+ "Only found instances in the configured Cylinder Shape intersection area",
+ "Found instances outside of the configured Cylinder Shape intersection area"
+ )
+ preprocess_instance_count = (
+ "Found the expected number of instances with preprocessing filter stage",
+ "Found an unexpected number of instances with preprocessing filter stage"
+ )
+ postprocess_instance_count = (
+ "Found the expected number of instances with postprocessing filter stage",
+ "Found an unexpected number of instances with postprocessing filter stage"
+ )
+
+
+def ShapeIntersectionFilter_FilterStageToggle():
+ """
+ Summary:
+ Filter Stage toggle affects final vegetation position
+
+ Expected Result:
+ Vegetation instances plant differently depending on the Filter Stage setting. With PreProcess, some vegetation
+ instances can appear on slopes outside the filtered values. With PostProcess, vegetation instances only appear on
+ the correct slope values.
+
+ :return: None
+ """
+
+ import os
+
+ import azlmbr.math as math
+ import azlmbr.legacy.general as general
+
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+
+ general.set_current_view_position(512.0, 480.0, 38.0)
+
+ # Create basic vegetation entity
+ position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
+
+ # Create Surface for instances to plant on
+ dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
+
+ # Add a Vegetation Shape Intersection Filter to the vegetation area entity
+ vegetation.add_component("Vegetation Shape Intersection Filter")
+
+ # Create a new entity as a child of the vegetation area entity with Box Shape
+ box = hydra.Entity("box")
+ box.create_entity(position, ["Box Shape"])
+ box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(8.0, 8.0, 1.0))
+
+ # Create a new entity as a child of the vegetation area entity with Cylinder Shape.
+ cylinder = hydra.Entity("cylinder")
+ cylinder.create_entity(position, ["Cylinder Shape"])
+ cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
+ cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
+ box.set_test_parent_entity(vegetation)
+ cylinder.set_test_parent_entity(vegetation)
+
+ # On the Shape Intersection Filter component, click the crosshair button, and add child entities one by one
+ vegetation.get_set_test(3, "Configuration|Shape Entity Id", box.id)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0, 100), 2.0)
+ Report.result(Tests.instance_count_in_box_shape, result)
+ vegetation.get_set_test(3, "Configuration|Shape Entity Id", cylinder.id)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 100), 2.0)
+ Report.result(Tests.instance_count_in_cylinder_shape, result)
+
+ # Create a new entity as a child of the area entity with Random Noise Gradient, Gradient Transform Modifier,
+ # and Box Shape component
+ random_noise = hydra.Entity("random_noise")
+ random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
+ random_noise.set_test_parent_entity(vegetation)
+
+ # Add a Vegetation Position Modifier to the vegetation area entity
+ vegetation.add_component("Vegetation Position Modifier")
+
+ # Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
+ vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
+
+ # Toggle between PreProcess and PostProcess
+ vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 117), 2.0)
+ Report.result(Tests.preprocess_instance_count, result)
+ vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 122), 2.0)
+ Report.result(Tests.postprocess_instance_count, result)
+
+
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(ShapeIntersectionFilter_FilterStageToggle)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py
index 83458fe153..e872b23054 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py
@@ -5,124 +5,126 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C4874094: Shape reference can be replaced/removed
-"""
-import os
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.bus as bus
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ instance_count_in_box_shape = (
+ "Only found instances in the configured Box Shape intersection area",
+ "Found instances outside of the configured Box Shape intersection area"
+ )
+ instance_count_in_cylinder_shape = (
+ "Only found instances in the configured Cylinder Shape intersection area",
+ "Found instances outside of the configured Cylinder Shape intersection area"
+ )
+ unfiltered_instance_count = (
+ "Found instances in the entire Spawner area with no filter set",
+ "Failed to find all expected instances in the Spawner area with no filter set"
+ )
-class TestShapeIntersectionFilter(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="ShapeIntersectionFilter_InstancePlanting", args=["level"])
+def ShapeIntersectionFilter_InstancesPlantInAssignedShape():
+ """
+ Summary:
+ A spawner area is created with a Vegetation Shape Intersection Filter. 2 different shape entities are created,
+ pinned to the Shape Intersection Filter, and instance counts are verified.
- def run_test(self):
- """
- Summary:
- A spawner area is created with a Vegetation Shape Intersection Filter. 2 different shape entities are created,
- pinned to the Shape Intersection Filter, and instance counts are verified.
+ Expected Behavior:
+ The Shape Entity Id reference can be successfully set/updated. Instances spawn only in the specified shape area.
- Expected Behavior:
- The Shape Entity Id reference can be successfully set/updated. Instances spawn only in the specified shape area.
+ Test Steps:
+ 1) Open an existing level, and set view for visual debugging
+ 2) Create an instance spawner and planting surface
+ 3) Create child entity with Box Shape
+ 4) Create child entity with Cylinder Shape
+ 5) Assign the Intersection Filter to the Box Shape and validate instance counts
+ 6) Assign the Intersection Filter to the Cylinder Shape and validate instance counts
+ 7) Remove the shape reference on the Intersection Filter and validate instance counts
- Test Steps:
- 1) Create a new level, and set view for visual debugging
- 2) Create an instance spawner and planting surface
- 3) Create child entity with Box Shape
- 4) Create child entity with Cylinder Shape
- 5) Assign the Intersection Filter to the Box Shape and validate instance counts
- 6) Assign the Intersection Filter to the Cylinder Shape and validate instance counts
- 7) Remove the shape reference on the Intersection Filter and validate instance counts
+ 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 a new, temporary 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
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.bus as bus
+ import azlmbr.math as math
- # 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
- asset_path)
- spawner_entity.add_component("Vegetation Shape Intersection Filter")
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Create a planting surface
- dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 3) Create a child entity with Box Shape
- components_to_add = ["Box Shape"]
- box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
- box = hydra.Entity("Box", box_id)
- box.components = []
- for component in components_to_add:
- box.components.append(hydra.add_component(component, box_id))
- new_box_dimension = math.Vector3(5.0, 5.0, 5.0)
- hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 4) Create a child entity with Cylinder Shape
- components_to_add = ["Cylinder Shape"]
- cylinder_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
- cylinder = hydra.Entity("Cylinder", cylinder_id)
- cylinder.components = []
- for component in components_to_add:
- cylinder.components.append(hydra.add_component(component, cylinder_id))
- hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
+ # 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0,
+ asset_path)
+ spawner_entity.add_component("Vegetation Shape Intersection Filter")
- # 5) Set the Intersection Filter's Shape Entity Id to the Box Shape entity
- spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", box_id)
+ # Create a planting surface
+ dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
- # Validate instance counts. Instances should only plant in the Box Shape area
- num_expected = 49
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
-
- # 6) Set the Intersection Filter's Shape Entity Id to the Cylinder Shape entity
- spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", cylinder_id)
+ # 3) Create a child entity with Box Shape
+ components_to_add = ["Box Shape"]
+ box_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
+ box = hydra.Entity("Box", box_id)
+ box.components = []
+ for component in components_to_add:
+ box.components.append(hydra.add_component(component, box_id))
+ new_box_dimension = math.Vector3(5.0, 5.0, 5.0)
+ hydra.get_set_test(box, 0, "Box Shape|Box Configuration|Dimensions", new_box_dimension)
- # Validate instance counts. Instances should only plant in the Cylinder Shape area
- num_expected = 121
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ # 4) Create a child entity with Cylinder Shape
+ components_to_add = ["Cylinder Shape"]
+ cylinder_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
+ cylinder = hydra.Entity("Cylinder", cylinder_id)
+ cylinder.components = []
+ for component in components_to_add:
+ cylinder.components.append(hydra.add_component(component, cylinder_id))
+ hydra.get_set_test(cylinder, 0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
- # 7) Clear the Intersection Filter's Shape Entity Id reference
- spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", None)
+ # 5) Set the Intersection Filter's Shape Entity Id to the Box Shape entity
+ spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", box_id)
- # Validate instance counts. Instances should now fill the entire spawner_entity's area
- num_expected = 20 * 20
- success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 5.0)
- self.test_success = success and self.test_success
+ # Validate instance counts. Instances should only plant in the Box Shape area
+ num_expected = 49
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.instance_count_in_box_shape, success)
+
+ # 6) Set the Intersection Filter's Shape Entity Id to the Cylinder Shape entity
+ spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", cylinder_id)
+
+ # Validate instance counts. Instances should only plant in the Cylinder Shape area
+ num_expected = 121
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.instance_count_in_cylinder_shape, success)
+
+ # 7) Clear the Intersection Filter's Shape Entity Id reference
+ spawner_entity.get_set_test(3, "Configuration|Shape Entity Id", None)
+
+ # Validate instance counts. Instances should now fill the entire spawner_entity's area
+ num_expected = 20 * 20
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 5.0)
+ Report.result(Tests.unfiltered_instance_count, success)
-test = TestShapeIntersectionFilter()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(ShapeIntersectionFilter_InstancesPlantInAssignedShape)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py
index abd3dc35d5..5855972f0c 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py
@@ -5,121 +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
-from math import radians
-import sys
-import azlmbr.areasystem as areasystem
-import azlmbr.asset as asset
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ surface_entity_created = (
+ "Successfully created Surface entity",
+ "Failed to create Surface entity"
+ )
+ instance_count = (
+ "Found the expected number of instances",
+ "Unexpected number of instances found"
+ )
+ instances_aligned_0 = (
+ "All instances are pointed straight up",
+ "Found instances not aligned to surface pointing straight up"
+ )
+ instances_aligned_1 = (
+ "All instances are planted perpendicularly to the surface",
+ "Found instances not aligned to surface perpendicularly"
+ )
-class TestSlopeAlignmentModifierOverrides(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SlopeAlignmentModifierOverrides", args=["level"])
+def SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment():
+ """
+ Summary:
+ Verifies instances properly align to surfaces based on configuration of descriptor overrides of the
+ Vegetation Slope Alignment Modifier component.
- def run_test(self):
- """
- Summary:
- C4814459 Verifies instances properly align to surfaces based on configuration of descriptor overrides of the
- Vegetation Slope Alignment Modifier component.
+ :return: None
+ """
- :return: None
- """
+ import os
+ from math import radians
- def verify_proper_alignment(instance, rot_degrees_vec):
- expected_rotation = math.Quaternion()
- expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
- if instance.alignment.IsClose(expected_rotation):
- return True
- self.log(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
- return False
+ import azlmbr.areasystem as areasystem
+ import azlmbr.asset as asset
+ import azlmbr.bus as bus
+ import azlmbr.components as components
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # 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,
- )
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- general.set_current_view_position(512.0, 480.0, 38.0)
+ def verify_proper_alignment(instance, rot_degrees_vec):
+ expected_rotation = math.Quaternion()
+ expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
+ if instance.alignment.IsClose(expected_rotation):
+ return True
+ Report.info(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
+ return False
- # Create a spawner entity setup with all needed components
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create a sloped mesh surface for the instances to plant on
- center_point = math.Vector3(502.0, 512.0, 24.0)
- mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
- mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
- False)
- rotation = math.Vector3(0.0, radians(45.0), 0.0)
- surface_entity = hydra.Entity("Surface Entity")
- surface_entity.create_entity(
- center_point,
- ["Mesh", "Mesh Surface Tag Emitter"]
- )
- if surface_entity.id.IsValid():
- print(f"'{surface_entity.name}' created")
- hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
- components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
- components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Add a Vegetation Debugger component to allow refreshing instances
- hydra.add_level_component("Vegetation Debugger")
+ # Create a spawner entity setup with all needed components
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
- # Add Vegetation Slope Alignment Modifier to the spawner entity and toggle on Allow Per-Item Overrides
- spawner_entity.add_component("Vegetation Slope Alignment Modifier")
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ # Create a sloped mesh surface for the instances to plant on
+ center_point = math.Vector3(502.0, 512.0, 24.0)
+ mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
+ mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
+ False)
+ rotation = math.Vector3(0.0, radians(45.0), 0.0)
+ surface_entity = hydra.Entity("Surface Entity")
+ surface_entity.create_entity(
+ center_point,
+ ["Mesh", "Mesh Surface Tag Emitter"]
+ )
+ Report.critical_result(Tests.surface_entity_created, surface_entity.id.IsValid())
+ hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
+ components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
+ components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
- # Toggle on Surface Slope Alignment Override Enabled on the Vegetation Asset List component
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Override Enabled",
- True)
+ # Add a Vegetation Debugger component to allow refreshing instances
+ hydra.add_level_component("Vegetation Debugger")
- # Set Surface Slope Alignment Override Min and Max to 0 and validate instance alignment
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
+ # Add Vegetation Slope Alignment Modifier to the spawner entity and toggle on Allow Per-Item Overrides
+ spawner_entity.add_component("Vegetation Slope Alignment Modifier")
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
- # Verify instances are have planted and are aligned to slope as expected
- num_expected = 20 * 20
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ # Toggle on Surface Slope Alignment Override Enabled on the Vegetation Asset List component
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Override Enabled",
+ True)
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ # Set Surface Slope Alignment Override Min and Max to 0 and validate instance alignment
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 0.0)
- if self.test_success and num_expected == len(instances):
- for instance in instances:
- self.test_success = verify_proper_alignment(instance,
- math.Vector3(0.0, 0.0, 0.0)) and self.test_success
+ # Verify instances are have planted and are aligned to slope as expected
+ num_expected = 20 * 20
+ instances_planted = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, instances_planted)
- # Set Surface Slope Alignment Min and Max to 1 and validate instance alignment
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Min", 1.0)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 1.0)
- general.run_console('veg_debugClearAllAreas')
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ success = True
+ for instance in instances:
+ success = verify_proper_alignment(instance, math.Vector3(0.0, 0.0, 0.0))
+ Report.result(Tests.instances_aligned_0, success)
- if self.test_success and num_expected == len(instances):
- for instance in instances:
- self.test_success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0)) and \
- self.test_success
+ # Set Surface Slope Alignment Min and Max to 1 and validate instance alignment
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Min", 1.0)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max", 1.0)
+ general.run_console('veg_debugClearAllAreas')
+ instances_planted = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, instances_planted)
+
+ box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+
+ success = True
+ for instance in instances:
+ success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0))
+ Report.result(Tests.instances_aligned_1, success)
-test = TestSlopeAlignmentModifierOverrides()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py
index 6e9e36957f..11427b9b0e 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py
@@ -5,127 +5,139 @@ 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
-from math import radians
-import sys
-import azlmbr.areasystem as areasystem
-import azlmbr.asset as asset
-import azlmbr.bus as bus
-import azlmbr.components as components
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ surface_entity_created = (
+ "Successfully created Surface entity",
+ "Failed to create Surface entity"
+ )
+ instance_count = (
+ "Found the expected number of instances",
+ "Unexpected number of instances found"
+ )
+ instances_aligned_1 = (
+ "All instances are planted perpendicularly to the surface",
+ "Found instances not aligned to surface perpendicularly"
+ )
+ instances_aligned_0 = (
+ "All instances are pointed straight up",
+ "Found instances not aligned to surface pointing straight up"
+ )
-class TestSlopeAlignmentModifier(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SlopeAlignmentModifier", args=["level"])
+def SlopeAlignmentModifier_InstanceSurfaceAlignment():
+ """
+ Summary:
+ Verifies instances properly align to surfaces based on configuration of the Vegetation Slope Alignment
+ Modifier.
- def run_test(self):
- """
- Summary:
- C4896941 Verifies instances properly align to surfaces based on configuration of the Vegetation Slope Alignment
- Modifier.
+ :return: None
+ """
- :return: None
- """
+ import os
+ from math import radians
- def verify_proper_alignment(instance, rot_degrees_vec):
- expected_rotation = math.Quaternion()
- expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
- if instance.alignment.IsClose(expected_rotation):
- return True
- self.log(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
- return False
+ import azlmbr.areasystem as areasystem
+ import azlmbr.asset as asset
+ import azlmbr.bus as bus
+ import azlmbr.components as components
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # 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,
- )
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- general.set_current_view_position(512.0, 480.0, 38.0)
+ def verify_proper_alignment(instance, rot_degrees_vec):
+ expected_rotation = math.Quaternion()
+ expected_rotation.SetFromEulerDegrees(rot_degrees_vec)
+ if instance.alignment.IsClose(expected_rotation):
+ return True
+ Report.info(f"Expected rotation of {expected_rotation}, Found {instance.alignment}")
+ return False
- # Create a spawner entity setup with all needed components
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Create a sloped mesh surface for the instances to plant on
- center_point = math.Vector3(502.0, 512.0, 24.0)
- mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
- mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
- False)
- rotation = math.Vector3(0.0, radians(45.0), 0.0)
- surface_entity = hydra.Entity("Surface Entity")
- surface_entity.create_entity(
- center_point,
- ["Mesh", "Mesh Surface Tag Emitter"]
- )
- if surface_entity.id.IsValid():
- print(f"'{surface_entity.name}' created")
- hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
- components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
- components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Add a Vegetation Debugger component to allow refreshing instances
- hydra.add_level_component("Vegetation Debugger")
+ # Create a spawner entity setup with all needed components
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path)
- # Add Vegetation Slope Alignment Modifier to the spawner entity
- spawner_entity.add_component("Vegetation Slope Alignment Modifier")
+ # Create a sloped mesh surface for the instances to plant on
+ center_point = math.Vector3(502.0, 512.0, 24.0)
+ mesh_asset_path = os.path.join("objects", "_primitives", "_box_1x1.azmodel")
+ mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
+ False)
+ rotation = math.Vector3(0.0, radians(45.0), 0.0)
+ surface_entity = hydra.Entity("Surface Entity")
+ surface_entity.create_entity(
+ center_point,
+ ["Mesh", "Mesh Surface Tag Emitter"]
+ )
+ Report.critical_result(Tests.surface_entity_created, surface_entity.id.IsValid())
+ hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
+ components.TransformBus(bus.Event, "SetLocalRotation", surface_entity.id, rotation)
+ components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, 30.0)
- # Set Alignment Coefficient Min/Max to 1 on the Slope Alignment Modifier
- spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 1.0)
- spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 1.0)
+ # Add a Vegetation Debugger component to allow refreshing instances
+ hydra.add_level_component("Vegetation Debugger")
- # Create new child entity with a Constant Gradient
- child_vegetation_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
- child_vegetation = hydra.Entity("Child Vegetation Entity", child_vegetation_id)
- components_to_add = ["Constant Gradient"]
- child_vegetation.components = []
- for component in components_to_add:
- child_vegetation.components.append(hydra.add_component(component, child_vegetation_id))
+ # Add Vegetation Slope Alignment Modifier to the spawner entity
+ spawner_entity.add_component("Vegetation Slope Alignment Modifier")
- # Reference the Constant Gradient on the Slope Alignment Modifier component
- spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", child_vegetation_id)
+ # Set Alignment Coefficient Min/Max to 1 on the Slope Alignment Modifier
+ spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 1.0)
+ spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 1.0)
- # Verify instances are have planted and are aligned to slope as expected
- num_expected = 20 * 20
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ # Create new child entity with a Constant Gradient
+ child_vegetation_id = editor.ToolsApplicationRequestBus(bus.Broadcast, "CreateNewEntity", spawner_entity.id)
+ child_vegetation = hydra.Entity("Child Vegetation Entity", child_vegetation_id)
+ components_to_add = ["Constant Gradient"]
+ child_vegetation.components = []
+ for component in components_to_add:
+ child_vegetation.components.append(hydra.add_component(component, child_vegetation_id))
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ # Reference the Constant Gradient on the Slope Alignment Modifier component
+ spawner_entity.get_set_test(3, "Configuration|Gradient|Gradient Entity Id", child_vegetation_id)
- if self.test_success and num_expected == len(instances):
- for instance in instances:
- self.test_success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0)) and \
- self.test_success
+ # Verify instances are have planted and are aligned to slope as expected
+ num_expected = 20 * 20
+ instances_planted = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, instances_planted)
- # Change Min/Max to 0.0 and verify proper alignment
- spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 0.0)
- spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 0.0)
- general.run_console('veg_debugClearAllAreas')
- self.test_success = self.test_success and self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
- box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+ success = True
+ for instance in instances:
+ success = verify_proper_alignment(instance, math.Vector3(0.0, 45.0, 0.0))
+ Report.result(Tests.instances_aligned_1, success)
- if self.test_success and num_expected == len(instances):
- for instance in instances:
- self.test_success = verify_proper_alignment(instance, math.Vector3(0.0, 0.0, 0.0)) and self.test_success
+ # Change Min/Max to 0.0 and verify proper alignment
+ spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Min", 0.0)
+ spawner_entity.get_set_test(3, "Configuration|Alignment Coefficient Max", 0.0)
+ general.run_console('veg_debugClearAllAreas')
+ instances_planted = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.critical_result(Tests.instance_count, instances_planted)
+
+ box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
+ instances = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstancesInAabb', box)
+
+ success = True
+ for instance in instances:
+ success = verify_proper_alignment(instance, math.Vector3(0.0, 0.0, 0.0))
+ Report.result(Tests.instances_aligned_0, success)
-test = TestSlopeAlignmentModifier()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SlopeAlignmentModifier_InstanceSurfaceAlignment)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py
index d66716cee3..ee0851d552 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py
@@ -5,121 +5,122 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C4874096 - Slope Min/Max properties can be set, and properly affect planted vegetation
-C4814464 - Slope Filter overrides function as expected
-"""
-import os
-import sys
-
-import azlmbr.bus as bus
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ prefilter_instance_count = (
+ "Found the expected number of instances before applying the Slope Filter",
+ "Found an unexpected number of instances before applying the Slope Filter"
+ )
+ postfilter_instance_count = (
+ "Found the expected number of instances after applying the Slope Filter",
+ "Found an unexpected number of instances after applying the Slope Filter"
+ )
+ postfilter_overrides_instance_count = (
+ "Found the expected number of instances after applying descriptor overrides to the Slope Filter",
+ "Found an unexpected number of instances after applying descriptor overrides to the Slope Filter"
+ )
-class TestSlopeFilterComponentAndOverrides(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SlopeFilter_InstancesPlantOnValidSlope", args=["level"])
+def SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes():
+ """
+ Summary:
+ An existing level is opened. A spawner entity is added, along with a flat planting surface at 32 on Z, and sphere
+ mesh at 38 on Z to provide a sloped surface. A Slope Filter is added to the spawner entity, and Slope Min/Max
+ values are set. Instance counts are validated. The same test is then performed for Slope Filter overrides.
- def run_test(self):
- """
- Summary:
- A new level is created. A spawner entity is added, along with a flat planting surface at 32 on Z, and sphere
- mesh at 38 on Z to provide a sloped surface. A Slope Filter is added to the spawner entity, and Slope Min/Max
- values are set. Instance counts are validated. The same test is then performed for Slope Filter overrides.
+ Expected Behavior:
+ Instances plant only on surfaces that fall between the Slope Filter Min/Max settings
- Expected Behavior:
- Instances plant only on surfaces that fall between the Slope Filter Min/Max settings
+ Test Steps:
+ 1) Open an existing level
+ 2) Create an instance spawner entity
+ 3) Create surfaces to plant on, one at 32 on Z and another sloped surface at 38 on Z.
+ 4) Initial instance counts pre-filter are verified.
+ 5) Slope Min/Max values are set on the Slope Filter component
+ 6) Instance counts are validated
+ 7) Setup for overrides tests
+ 8) Slope Min/Max values are set on the descriptor overrides
+ 9) Instance counts are validated
- Test Steps:
- 1) Create a new level
- 2) Create an instance spawner entity
- 3) Create surfaces to plant on, one at 32 on Z and another sloped surface at 38 on Z.
- 4) Initial instance counts pre-filter are verified.
- 5) Slope Min/Max values are set on the Slope Filter component
- 6) Instance counts are validated
- 7) Setup for overrides tests
- 8) Slope Min/Max values are set on the descriptor overrides
- 9) Instance counts are validated
+ 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
- # 1) Create a new, temporary 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 azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 475.0, 38.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new entity with required vegetation area components
- center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Add a Vegetation Slope Filter
- spawner_entity.add_component("Vegetation Slope Filter")
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 475.0, 38.0)
- # 3) Add surfaces to plant on. This will include a flat surface and a sphere mesh to provide a sloped surface
- dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
- sloped_surface_center = math.Vector3(512.0, 512.0, 38.0)
- dynveg.create_mesh_surface_entity_with_slopes("Sloped Planting Surface", sloped_surface_center, 10.0)
+ # 2) Create a new entity with required vegetation area components
+ center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path)
- # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
- 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
+ # Add a Vegetation Slope Filter
+ spawner_entity.add_component("Vegetation Slope Filter")
- # 4) Validate instance counts pre-filter
- num_expected_flat_surface = 40 * 40 # 20x20 instances per 16m
- num_expected_slopes_pre_filter = 120 # Unfiltered planting on the top of the sphere mesh
- num_expected = num_expected_flat_surface + num_expected_slopes_pre_filter
- initial_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
- spawner_entity.id, num_expected), 5.0)
- self.test_success = initial_success and self.test_success
+ # 3) Add surfaces to plant on. This will include a flat surface and a sphere mesh to provide a sloped surface
+ dynveg.create_surface_entity("Planting Surface", center_point, 32.0, 32.0, 1.0)
+ sloped_surface_center = math.Vector3(512.0, 512.0, 38.0)
+ dynveg.create_mesh_surface_entity_with_slopes("Sloped Planting Surface", sloped_surface_center, 10.0)
- # 5) Change Slope Min/Max on the Vegetation Slope Filter component
- spawner_entity.get_set_test(3, "Configuration|Slope Min", 20)
- spawner_entity.get_set_test(3, "Configuration|Slope Max", 45)
+ # Set instances to spawn on a center snap point to avoid unexpected instances around the edges of the box shape
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", veg_system_settings_component,
+ 'Configuration|Area System Settings|Sector Point Snap Mode', 1)
- # 6) Validate instance counts post-filter: instances should only plant on slopes between 20-45 degrees
- num_expected_slopes_post_filter = 48
- slope_min_max_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
- spawner_entity.id, num_expected_slopes_post_filter), 5.0)
- self.test_success = slope_min_max_success and self.test_success
+ # 4) Validate instance counts pre-filter
+ num_expected_flat_surface = 40 * 40 # 20x20 instances per 16m
+ num_expected_slopes_pre_filter = 120 # Unfiltered planting on the top of the sphere mesh
+ num_expected = num_expected_flat_surface + num_expected_slopes_pre_filter
+ initial_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
+ spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.prefilter_instance_count, initial_success)
- # 7) Setup for overrides on the Slope Filter component and the spawner entity's descriptor
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Override Enabled", True)
+ # 5) Change Slope Min/Max on the Vegetation Slope Filter component
+ spawner_entity.get_set_test(3, "Configuration|Slope Min", 20)
+ spawner_entity.get_set_test(3, "Configuration|Slope Max", 45)
- # 8) Set Slope Filter Min/Max overrides on the spawner entity's descriptor
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Min", 5)
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Max", 20)
+ # 6) Validate instance counts post-filter: instances should only plant on slopes between 20-45 degrees
+ num_expected_slopes_post_filter = 48
+ slope_min_max_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
+ spawner_entity.id, num_expected_slopes_post_filter), 5.0)
+ Report.result(Tests.postfilter_instance_count, slope_min_max_success)
- # 9) Validate instance counts post-filter: instances should only plant on slopes between 5-20 degrees
- num_expected_slopes_post_filter_overrides = 12
- overrides_min_max_success = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
- spawner_entity.id, num_expected_slopes_post_filter_overrides), 5.0)
- self.test_success = overrides_min_max_success and self.test_success
+ # 7) Setup for overrides on the Slope Filter component and the spawner entity's descriptor
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Override Enabled", True)
+
+ # 8) Set Slope Filter Min/Max overrides on the spawner entity's descriptor
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Min", 5)
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]|Slope Filter|Max", 20)
+
+ # 9) Validate instance counts post-filter: instances should only plant on slopes between 5-20 degrees
+ num_expected_slopes_post_filter_overrides = 12
+ overrides_min_max_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(
+ spawner_entity.id, num_expected_slopes_post_filter_overrides), 5.0)
+ Report.result(Tests.postfilter_overrides_instance_count, overrides_min_max_success)
-test = TestSlopeFilterComponentAndOverrides()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_FilterStageToggle.py
deleted file mode 100755
index 33275f2992..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_FilterStageToggle.py
+++ /dev/null
@@ -1,103 +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.bus as bus
-import azlmbr.paths
-import azlmbr.editor as editor
-import azlmbr.entity as EntityId
-import azlmbr.components as components
-import azlmbr.legacy.general as general
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
-
-class TestSlopeFilterFilterStageToggle(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SlopeFilter_FilterStageToggle", args=["level"])
-
- def run_test(self):
- """
- Summary:
- Filter Stage toggle affects final vegetation position
-
- Expected Result:
- Vegetation instances plant differently depending on the Filter Stage setting. With PreProcess, some vegetation instances can
- appear on slopes outside the filtered values. With PostProcess, vegetation instances only appear on the correct slope values.
-
- :return: None
- """
-
- # 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,
- )
-
- general.set_current_view_position(512.0, 480.0, 38.0)
-
- # Create basic vegetation entity
- position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path)
-
- # Create Surface for instances to plant on
- dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
-
- # Add a Vegetation Shape Intersection Filter to the vegetation area entity
- vegetation.add_component("Vegetation Shape Intersection Filter")
-
- # Create a new entity as a child of the vegetation area entity with Box Shape
- box = hydra.Entity("box")
- box.create_entity(position, ["Box Shape"])
- box.get_set_test(0, "Box Shape|Box Configuration|Dimensions", math.Vector3(8.0, 8.0, 1.0))
-
- # Create a new entity as a child of the vegetation area entity with Cylinder Shape.
- cylinder = hydra.Entity("cylinder")
- cylinder.create_entity(position, ["Cylinder Shape"])
- cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Radius", 5.0)
- cylinder.get_set_test(0, "Cylinder Shape|Cylinder Configuration|Height", 5.0)
- box.set_test_parent_entity(vegetation)
- cylinder.set_test_parent_entity(vegetation)
-
- # # On the Vegetation Shape Intersection Filter component, click the crosshair button, and add child entities one by one
- vegetation.get_set_test(3, "Configuration|Shape Entity Id", box.id)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0, 100), 2.0)
- self.log(f"Vegetation plant only in the areas where the Box overlaps with the vegetation area's boundaries: {result}")
- vegetation.get_set_test(3, "Configuration|Shape Entity Id", cylinder.id)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 100), 2.0)
- self.log(f"Vegetation plant only in the areas where the Cylinder overlaps with the vegetation area's boundaries: {result}")
-
- # Create a new entity as a child of the vegetation area entity with Random Noise Gradient Generator, Gradient Transform Modifier,
- # and Box Shape component
- random_noise = hydra.Entity("random_noise")
- random_noise.create_entity(position, ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"])
- random_noise.set_test_parent_entity(vegetation)
-
- # Add a Vegetation Position Modifier to the vegetation area entity
- vegetation.add_component("Vegetation Position Modifier")
-
- # Pin the Random Noise entity to the Gradient Entity Id field of the Position Modifier's Gradient X
- vegetation.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", random_noise.id)
-
- # Toggle between PreProcess and PostProcess
- vegetation.get_set_test(3, "Configuration|Filter Stage", 1)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 117), 2.0)
- self.log(f"Vegetation instances count equal to expected value for PREPROCESS filter stage: {result}")
- vegetation.get_set_test(3, "Configuration|Filter Stage", 2)
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count(position, 5.0, 122), 2.0)
- self.log(f"Vegetation instances count equal to expected value for POSTPROCESS filter stage: {result}")
-
-test = TestSlopeFilterFilterStageToggle()
-test.run()
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py
new file mode 100644
index 0000000000..1658ffc532
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py
@@ -0,0 +1,126 @@
+"""
+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:
+ spawner_slice_created = (
+ "Spawner slice created successfully",
+ "Failed to create Spawner slice"
+ )
+ instance_count_unhidden = (
+ "Initial instance counts are as expected",
+ "Found an unexpected number of initial instances"
+ )
+ instance_count_hidden = (
+ "Instance counts upon hiding the Spawner slice are as expected",
+ "Unexpectedly found instances with the Spawner slice hidden"
+ )
+ blender_slice_created = (
+ "Blender slice created successfully",
+ "Failed to create Blender slice"
+ )
+
+
+def SpawnerSlices_SliceCreationAndVisibilityToggleWorks():
+ """
+ Summary:
+ C2627900 Verifies if a slice containing the component can be created.
+ C2627905 A slice containing the Vegetation Layer Blender component can be created.
+ C2627904: Hiding a slice containing the component clears any visuals from the Viewport.
+
+ Expected Result:
+ C2627900, C2627905: Slice is created, and is properly processed in the Asset Processor.
+ C2627904: Vegetation area visuals are hidden from the Viewport.
+
+ :return: None
+ """
+
+ import os
+
+ import azlmbr.math as math
+ import azlmbr.legacy.general as general
+ import azlmbr.slice as slice
+ import azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.asset as asset
+
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ def path_is_valid_asset(asset_path):
+ asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False)
+ return asset_id.invoke("IsValid")
+
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+ general.set_current_view_position(512.0, 480.0, 38.0)
+
+ # 2) C2627900 Verifies if a slice containing the Vegetation Layer Spawner component can be created.
+ # 2.1) Create basic vegetation entity
+ position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ veg_1 = dynveg.create_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path)
+
+ # 2.2) Create slice from the entity
+ slice_path = os.path.join("slices", "TestSlice_1.slice")
+ slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", veg_1.id, slice_path)
+
+ # 2.3) Verify if the slice has been created successfully
+ spawner_slice_success = helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
+ Report.result(Tests.spawner_slice_created, spawner_slice_success)
+
+ # 3) C2627904: Hiding a slice containing the component clears any visuals from the Viewport
+ # 3.1) Create Surface for instances to plant on
+ dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
+
+ # 3.2) Initially verify instance count before hiding slice
+ initial_count_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 5.0)
+ Report.result(Tests.instance_count_unhidden, initial_count_success)
+
+ # 3.3) Hide the slice and verify instance count
+ editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, False)
+ hidden_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0), 5.0)
+ Report.result(Tests.instance_count_hidden, hidden_instance_count)
+
+ # 3.4) Unhide the slice
+ editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, True)
+
+ # 4) C2627905 A slice containing the Vegetation Layer Blender component can be created.
+ # 4.1) Create another vegetation entity to add to blender component
+ veg_2 = dynveg.create_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "")
+
+ # 4.2) Create entity with Vegetation Layer Blender
+ components_to_add = ["Box Shape", "Vegetation Layer Blender"]
+ blender_entity = hydra.Entity("blender_entity")
+ blender_entity.create_entity(position, components_to_add)
+
+ # 4.3) Pin both the vegetation areas to the blender entity
+ pte = hydra.get_property_tree(blender_entity.components[1])
+ path = "Configuration|Vegetation Areas"
+ pte.update_container_item(path, 0, veg_1.id)
+ pte.add_container_item(path, 1, veg_2.id)
+
+ # 4.4) Drag the simple vegetation areas under the Vegetation Layer Blender entity to create an entity hierarchy.
+ veg_1.set_test_parent_entity(blender_entity)
+ veg_2.set_test_parent_entity(blender_entity)
+
+ # 4.5) Create slice from blender entity
+ slice_path = os.path.join("slices", "TestSlice_2.slice")
+ slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", blender_entity.id, slice_path)
+
+ # 4.6) Verify if the slice has been created successfully
+ blender_slice_success = helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0)
+ Report.result(Tests.blender_slice_created, blender_slice_success)
+
+
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SpawnerSlices_SliceCreationAndVisibilityToggleWorks)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py
index 2f08d3963d..1ad4f305c3 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py
@@ -5,99 +5,97 @@ 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.legacy.general as general
-import azlmbr.math as math
+class Tests:
+ editor_remains_stable = (
+ "Editor did not crash following rapid surface data updates",
+ "Editor crashed"
+ )
-sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
-from editor_python_test_tools.editor_test_helper import EditorTestHelper
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+def SurfaceDataRefreshes_RemainsStable():
+ """
+ Summary:
+ The Vegetation Area System can intermittently crash when updating surface data and moving the camera
+ around rapidly. The situation occurs across multiple frames - the surface data updates, which triggers a bunch
+ of sector updates getting added to the update queue. Then in a subsequent frame, there is no active vegetation
+ area or surface data updates, which triggers "delete all sectors". The "delete all" wasn't deleting entries from
+ the update queue, so any unprocessed updates would continue to get processed. If any of those updates referenced
+ a sector that no longer exists, because the camera changed position, then it would assert and crash.
+
+ To repro this bug, this test loads an empty level with a large box shape emitting a surface, and then runs a tight
+ loop of camera movements and "surface changed" events that invalidate all surface points. Because this is a timing
+ issue, there's no guarantee that the test below will successfully cause the condition to occur, but it successfully
+ crashed every time it was tested locally prior to the bugfix.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
+
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
+
+ world_center = math.Vector3(512.0, 512.0, 32.0)
+
+ # Add an entity with a 1024 x 1024 box centered at 512,512.
+ surface_entity = dynveg.create_surface_entity("Surface Data", world_center, 1024.0, 1024.0, 1.0)
+
+ # Move the camera to the world center
+ general.set_current_view_position(world_center.x, world_center.y, world_center.z)
+
+ # 2) Perform the test. Since the conditions are extremely timing related, and every machine
+ # running the test can have different timing conditions, we run through a set of different
+ # combinations to try and cause the crash under as many scenarios as possible
+
+ loops_per_surface_changed = [3, 5, 5]
+ loops_per_camera_reset = [20, 20, 20]
+ camera_speed_per_loop = [10.0, 10.0, 15.0]
+
+ # Setting test success to false to make sure the toggle at the end accurately conveys the loop being successful
+ test_success = False
+
+ # Loop through all our attempted timing test cases to cause the crash pretty consistently.
+ for test_case in range(0,3):
+ Report.info(f'Starting test case {test_case}')
+ Report.info(f'Loops per surface changed: {loops_per_surface_changed[test_case]}')
+ Report.info(f'Loops per camera reset: {loops_per_camera_reset[test_case]}')
+ Report.info(f'Camera speed per loop: {camera_speed_per_loop[test_case]}')
+ for test_counter in range(0, 100):
+
+ # Every N loops, invalidate the entire set of surface data. It's mostly just important for this
+ # not to happen *every* iteration, since we need the vegetation system to bounce between having
+ # dirty surface points that cause sectors to be refreshed, and having no dirty surface points or
+ # active surface areas to trigger a "delete all sectors" condition.
+ if (test_counter % loops_per_surface_changed[test_case]) == 0:
+ azlmbr.surface_data.SurfaceDataSystemNotificationBus(azlmbr.bus.Broadcast,
+ 'OnSurfaceChanged',
+ surface_entity.id,
+ azlmbr.math.Aabb(),
+ azlmbr.math.Aabb())
+
+ # Move the camera back and forth along the X axis at just the right speed to invalidate sectors that are
+ # queued for updating but haven't updated yet, so that when they try to update they crash.
+ x_pos = world_center.x + ((test_counter % loops_per_camera_reset[test_case]) * camera_speed_per_loop[test_case])
+ general.set_current_view_position(x_pos, world_center.y, world_center.z)
+
+ Report.info(f'{test_counter}: {x_pos}')
+
+ # Give a little processing time each iteration.
+ general.idle_wait(0.01)
+
+ # If we haven't crashed, then we've succeeded.
+ test_success = True
+ Report.result(Tests.editor_remains_stable, test_success)
-class TestSurfaceDataRefreshes_RemainsStable(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SurfaceDataRefreshes_RemainsStable", args=["level"])
+if __name__ == "__main__":
- def run_test(self):
- """
- Summary:
- The Vegetation Area System can intermittently crash when updating surface data and moving the camera
- around rapidly. The situation occurs across multiple frames - the surface data updates, which triggers a bunch
- of sector updates getting added to the update queue. Then in a subsequent frame, there is no active vegetation
- area or surface data updates, which triggers "delete all sectors". The "delete all" wasn't deleting entries from
- the update queue, so any unprocessed updates would continue to get processed. If any of those updates referenced
- a sector that no longer exists, because the camera changed position, then it would assert and crash.
-
- To repro this bug, this test creates an empty level with a large box shape emitting a surface, and then runs a tight
- loop of camera movements and "surface changed" events that invalidate all surface points. Because this is a timing
- issue, there's no guarantee that the test below will successfully cause the condition to occur, but it successfully
- crashed every time it was tested locally prior to the bugfix.
-
- :return: None
- """
- # 1) Create a test level with the needed test setup
- self.test_success = self.create_level(
- self.get_arg('level'),
- heightmap_resolution=128,
- heightmap_meters_per_pixel=1,
- terrain_texture_resolution=128,
- use_terrain=False)
-
- world_center = math.Vector3(512.0, 512.0, 32.0)
-
- # Add an entity with a 1024 x 1024 box centered at 512,512.
- surface_entity = dynveg.create_surface_entity("Surface Data", world_center, 1024.0, 1024.0, 1.0)
-
- # Move the camera to the world center
- general.set_current_view_position(world_center.x, world_center.y, world_center.z)
-
- # 2) Perform the test. Since the conditions are extremely timing related, and every machine
- # running the test can have different timing conditions, we run through a set of different
- # combinations to try and cause the crash under as many scenarios as possible
-
- loops_per_surface_changed = [3, 5, 5]
- loops_per_camera_reset = [20, 20, 20]
- camera_speed_per_loop = [10.0, 10.0, 15.0]
-
- # Setting test success to false to make sure the toggle at the end accurately conveys the loop being successful
- self.test_success = False
-
- # Loop through all our attempted timing test cases to cause the crash pretty consistently.
- for test_case in range(0,3):
- self.log(f'Starting test case {test_case}')
- self.log(f'Loops per surface changed: {loops_per_surface_changed[test_case]}')
- self.log(f'Loops per camera reset: {loops_per_camera_reset[test_case]}')
- self.log(f'Camera speed per loop: {camera_speed_per_loop[test_case]}')
- for test_counter in range (0,100):
-
- # Every N loops, invalidate the entire set of surface data. It's mostly just important for this
- # not to happen *every* iteration, since we need the vegetation system to bounce between having
- # dirty surface points that cause sectors to be refreshed, and having no dirty surface points or
- # active surface areas to trigger a "delete all sectors" condition.
- if (test_counter % loops_per_surface_changed[test_case]) == 0:
- azlmbr.surface_data.SurfaceDataSystemNotificationBus(azlmbr.bus.Broadcast,
- 'OnSurfaceChanged',
- surface_entity.id,
- azlmbr.math.Aabb(),
- azlmbr.math.Aabb())
-
- # Move the camera back and forth along the X axis at just the right speed to invalidate sectors that are
- # queued for updating but haven't updated yet, so that when they try to update they crash.
- x_pos = world_center.x + ((test_counter % loops_per_camera_reset[test_case]) * camera_speed_per_loop[test_case])
- general.set_current_view_position(x_pos, world_center.y, world_center.z)
-
- self.log(f'{test_counter}: {x_pos}')
-
- # Give a little processing time each iteration.
- general.idle_wait(0.01)
-
- # If we haven't crashed, then we've succeeded.
- self.test_success = True
-
-
-test = TestSurfaceDataRefreshes_RemainsStable()
-test.run()
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SurfaceDataRefreshes_RemainsStable)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py
index 87aa7946b3..ba0f3e05e3 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py
@@ -5,153 +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
"""
-"""
-C3711666: Multiple Descriptors with different Surface Mask Filter overrides plant as expected.
-"""
-import os
-import sys
-
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-import azlmbr.paths
-import azlmbr.surface_data as surface_data
-
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_surface_validation = (
+ "Found all expected instances on all surfaces with initial setup",
+ "Found an unexpected number of instances on all surfaces with initial setup"
+ )
+ surface_a_validation = (
+ "Found the expected number of instances on Surface A",
+ "Found an unexpected number of instances on Surface A"
+ )
+ surface_b_validation = (
+ "Found the expected number of instances on Surface B",
+ "Found an unexpected number of instances on Surface B"
+ )
+ surface_c_validation = (
+ "Found the expected number of instances on Surface C",
+ "Found an unexpected number of instances on Surface C"
+ )
-class TestSurfaceMaskFilterMultipleOverrides(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_MultipleDescriptorOverrides", args=["level"])
+def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected():
+ """
+ Summary:
+ A new level is created. An instance spawner with 3 descriptors is created. 3 planting surfaces of different
+ sizes are created and different surface tags are applied to each. Descriptor surface mask filter overrides are
+ set and instance counts are validated.
- def run_test(self):
- """
- Summary:
- A new level is created. An instance spawner with 3 descriptors is created. 3 planting surfaces of different
- sizes are created and different surface tags are applied to each. Descriptor surface mask filter overrides are
- set and instance counts are validated.
+ Expected Behavior:
+ Instances plant on surfaces based on surface mask filter overrides.
- Expected Behavior:
- Instances plant on surfaces based on surface mask filter overrides.
+ Test Steps:
+ 1) Open an existing level
+ 2) An instance spawner with 3 descriptors is created, and a Surface Mask Filter is added to the entity
+ 3) 3 surfaces of different sizes are created, and set to emit different tags
+ 4) Pre-test validation of instances
+ 5) Test 1 setup and validation: Inclusion tag matching surface a is set on a single descriptor
+ 6) Test 2 setup and validation: Inclusion tag matching surface b is set on a single descriptor
+ 7) Test 3 setup and validation: Inclusion tag matching surface c is set on a single descriptor
- Test Steps:
- 1) A new level is created
- 2) An instance spawner with 3 descriptors is created, and a Surface Mask Filter is added to the entity
- 3) 3 surfaces of different sizes are created, and set to emit different tags
- 4) Pre-test validation of instances
- 5) Test 1 setup and validation: Inclusion tag matching surface a is set on a single descriptor
- 6) Test 2 setup and validation: Inclusion tag matching surface b is set on a single descriptor
- 7) Test 3 setup and validation: Inclusion tag matching surface c is set on a single descriptor
+ 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
- """
- surface_tag_list = [surface_data.SurfaceTag("test_tag"), surface_data.SurfaceTag("test_tag2"),
- surface_data.SurfaceTag("test_tag3")]
+ import os
- # 1) Create a new, temporary 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 azlmbr.legacy.general as general
+ import azlmbr.math as math
+ import azlmbr.surface_data as surface_data
- # Set view of planting area for visual debugging
- general.set_current_view_position(512.0, 500.0, 38.0)
- general.set_current_view_rotation(-20.0, 0.0, 0.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors
- spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
- asset_path)
- asset_list_component = spawner_entity.components[2]
- desc_asset = hydra.get_component_property_value(asset_list_component,
- "Configuration|Embedded Assets")[0]
- desc_list = [desc_asset, desc_asset, desc_asset]
- spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
-
- # Add a Surface Mask Filter component to the spawner entity and toggle on Allow Overrides
- spawner_entity.add_component("Vegetation Surface Mask Filter")
- spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
+ surface_tag_list = [surface_data.SurfaceTag("test_tag"), surface_data.SurfaceTag("test_tag2"),
+ surface_data.SurfaceTag("test_tag3")]
- # 3) Create 3 surfaces for planting, spaced out vertically, and set expected instance counts for each surface
- surface_entity_a = dynveg.create_surface_entity("Surface Entity A", math.Vector3(512.0, 512.0, 32.0),
- 16.0, 16.0, 1.0)
- num_expected_surface_a = 20 * 20 # 20x20 instances on a 16x16 meter surface
- surface_entity_b = dynveg.create_surface_entity("Surface Entity B", math.Vector3(512.0, 512.0, 35.0),
- 12.0, 12.0, 1.0)
- num_expected_surface_b = 15 * 15 # 15x15 instances on a 12x12 meter surface
- surface_entity_c = dynveg.create_surface_entity("Surface Entity C", math.Vector3(512.0, 512.0, 38.0),
- 8.0, 8.0, 1.0)
- num_expected_surface_c = 10 * 10 # 10x10 instances on a 8x8 meter surface
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Set each surface to emit a different tag
- surface_entity_a.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[0]])
- surface_entity_b.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[1]])
- surface_entity_c.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[2]])
+ # Set view of planting area for visual debugging
+ general.set_current_view_position(512.0, 500.0, 38.0)
+ general.set_current_view_rotation(-20.0, 0.0, 0.0)
- # 4) Initial Validation: Validate instance count in the spawner area. Instances should plant on all surfaces
- num_expected = num_expected_surface_a + num_expected_surface_b + num_expected_surface_c
- initial_success = self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
- self.test_success = initial_success and self.test_success
+ # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors
+ spawner_center_point = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0,
+ asset_path)
+ asset_list_component = spawner_entity.components[2]
+ desc_asset = hydra.get_component_property_value(asset_list_component,
+ "Configuration|Embedded Assets")[0]
+ desc_list = [desc_asset, desc_asset, desc_asset]
+ spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list)
- # 5)
- # Test #1 Setup: Set test_tag to inclusion list for descriptor 1. Set other descriptors to exclude all surfaces
+ # Add a Surface Mask Filter component to the spawner entity and toggle on Allow Overrides
+ spawner_entity.add_component("Vegetation Surface Mask Filter")
+ spawner_entity.get_set_test(3, "Configuration|Allow Per-Item Overrides", True)
- # Toggle on Display Per-Item Overrides and Surface Mask Filter Override for each descriptor
- for index in range(3):
- spawner_entity.get_set_test(2, f"Configuration|Embedded Assets|[{index}]|Display Per-Item Overrides", True)
- spawner_entity.get_set_test(2,
- f"Configuration|Embedded Assets|[{index}]|Surface Mask Filter|Override Mode", 1)
+ # 3) Create 3 surfaces for planting, spaced out vertically, and set expected instance counts for each surface
+ surface_entity_a = dynveg.create_surface_entity("Surface Entity A", math.Vector3(512.0, 512.0, 32.0),
+ 16.0, 16.0, 1.0)
+ num_expected_surface_a = 20 * 20 # 20x20 instances on a 16x16 meter surface
+ surface_entity_b = dynveg.create_surface_entity("Surface Entity B", math.Vector3(512.0, 512.0, 35.0),
+ 12.0, 12.0, 1.0)
+ num_expected_surface_b = 15 * 15 # 15x15 instances on a 12x12 meter surface
+ surface_entity_c = dynveg.create_surface_entity("Surface Entity C", math.Vector3(512.0, 512.0, 38.0),
+ 8.0, 8.0, 1.0)
+ num_expected_surface_c = 10 * 10 # 10x10 instances on a 8x8 meter surface
+ # Set each surface to emit a different tag
+ surface_entity_a.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[0]])
+ surface_entity_b.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[1]])
+ surface_entity_c.get_set_test(1, "Configuration|Generated Tags", [surface_tag_list[2]])
+
+ # 4) Initial Validation: Validate instance count in the spawner area. Instances should plant on all surfaces
+ num_expected = num_expected_surface_a + num_expected_surface_b + num_expected_surface_c
+ initial_success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected), 5.0)
+ Report.result(Tests.initial_surface_validation, initial_success)
+
+ # 5)
+ # Test #1 Setup: Set test_tag to inclusion list for descriptor 1. Set other descriptors to exclude all surfaces
+
+ # Toggle on Display Per-Item Overrides and Surface Mask Filter Override for each descriptor
+ for index in range(3):
+ spawner_entity.get_set_test(2, f"Configuration|Embedded Assets|[{index}]|Display Per-Item Overrides", True)
spawner_entity.get_set_test(2,
- "Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
- [surface_tag_list[0]])
- spawner_entity.get_set_test(2,
- "Configuration|Embedded Assets|[1]|Surface Mask Filter|Exclusion Tags",
- surface_tag_list)
- spawner_entity.get_set_test(2,
- "Configuration|Embedded Assets|[2]|Surface Mask Filter|Exclusion Tags",
- surface_tag_list)
+ f"Configuration|Embedded Assets|[{index}]|Surface Mask Filter|Override Mode", 1)
- # Test #1 Validation: Validate instance count. Should only plant on a single surface for 400 instances
- test_1_success = self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_a), 5.0)
- self.test_success = test_1_success and self.test_success
+ spawner_entity.get_set_test(2,
+ "Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
+ [surface_tag_list[0]])
+ spawner_entity.get_set_test(2,
+ "Configuration|Embedded Assets|[1]|Surface Mask Filter|Exclusion Tags",
+ surface_tag_list)
+ spawner_entity.get_set_test(2,
+ "Configuration|Embedded Assets|[2]|Surface Mask Filter|Exclusion Tags",
+ surface_tag_list)
- # 6)
- # Test #2 Setup: Set test_tag2 to inclusion for descriptor 1.
- spawner_entity.get_set_test(2,
- "Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
- [surface_tag_list[1]])
+ # Test #1 Validation: Validate instance count. Should only plant on a single surface for 400 instances
+ test_1_success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_a), 5.0)
+ Report.result(Tests.surface_a_validation, test_1_success)
- # Test #2 Validation: Validate instance count. Should only plant on a single surface for 225 instances
- test_2_success = self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_b), 5.0)
- self.test_success = test_2_success and self.test_success
+ # 6)
+ # Test #2 Setup: Set test_tag2 to inclusion for descriptor 1.
+ spawner_entity.get_set_test(2,
+ "Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
+ [surface_tag_list[1]])
- # 7)
- # Test #3 Setup: Set test_tag3 to inclusion for descriptor 1.
- spawner_entity.get_set_test(2,
- "Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
- [surface_tag_list[2]])
+ # Test #2 Validation: Validate instance count. Should only plant on a single surface for 225 instances
+ test_2_success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_b), 5.0)
+ Report.result(Tests.surface_b_validation, test_2_success)
- # Test #3 Validation: Validate instance count. Should only plant on a single surface for 100 instances
- test_3_success = self.wait_for_condition(
- lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_c), 5.0)
- self.test_success = test_3_success and self.test_success
+ # 7)
+ # Test #3 Setup: Set test_tag3 to inclusion for descriptor 1.
+ spawner_entity.get_set_test(2,
+ "Configuration|Embedded Assets|[0]|Surface Mask Filter|Inclusion Tags",
+ [surface_tag_list[2]])
+
+ # Test #3 Validation: Validate instance count. Should only plant on a single surface for 100 instances
+ test_3_success = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_surface_c), 5.0)
+ Report.result(Tests.surface_c_validation, test_3_success)
-test = TestSurfaceMaskFilterMultipleOverrides()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py
index 1baec7694d..fee62c04d1 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py
@@ -5,66 +5,61 @@ 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.surface_data as surface_data
-
-sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
-from editor_python_test_tools.editor_test_helper import EditorTestHelper
+class Tests:
+ tags_same_value_equal = (
+ "Two Surface Tags of the same value evaluated as equal",
+ "Two Surface Tags of the same value unexpectedly evaluated as unequal"
+ )
+ tags_different_value_unequal = (
+ "Two Surface Tags of different values evaluated as unequal",
+ "Two Surface Tags of different values unexpectedly evaluated as equal"
+ )
-class TestSurfaceMaskFilter_BasicSurfaceTagCreation(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="TestSurfaceMaskFilter_BasicSurfaceTagCreation", args=["level"])
-
- def run_test(self):
- """
- Summary:
- Verifies basic surface tag value equality
+def SurfaceMaskFilter_BasicSurfaceTagCreation():
+ """
+ Summary:
+ Verifies basic surface tag value equality
- Expected Behavior:
- Surface tags of the same name are equal, and different names aren't.
+ Expected Behavior:
+ Surface tags of the same name are equal, and different names aren't.
- Test Steps:
- 1) Open level
- 2) Create 2 new surface tags of identical names and verify they resolve as equal.
- 3) Create another new tag of a different name and verify they resolve as different.
+ Test Steps:
+ 1) Open level
+ 2) Create 2 new surface tags of identical names and verify they resolve as equal.
+ 3) Create another new tag of a different name and verify they resolve as different.
- 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
- """
- self.log("SurfaceTag test started")
-
- # Create a 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,
- )
-
- tag1 = surface_data.SurfaceTag()
- tag2 = surface_data.SurfaceTag()
-
- # Test 1: Verify that two tags with the same value are equal
- tag1.SetTag('equal_test')
- tag2.SetTag('equal_test')
- self.log("SurfaceTag equal tag comparison is {} expected True".format(tag1.Equal(tag2)))
- self.test_success = self.test_success and tag1.Equal(tag2)
-
- # Test 2: Verify that two tags with different values are not equal
- tag2.SetTag('not_equal_test')
- self.log("SurfaceTag not equal tag comparison is {} expected False".format(tag1.Equal(tag2)))
- self.test_success = self.test_success and not tag1.Equal(tag2)
-
- self.log("SurfaceTag test finished")
+ :return: None
+ """
+
+ import azlmbr.surface_data as surface_data
+ 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")
+
+ tag1 = surface_data.SurfaceTag()
+ tag2 = surface_data.SurfaceTag()
+
+ # Test 1: Verify that two tags with the same value are equal
+ tag1.SetTag('equal_test')
+ tag2.SetTag('equal_test')
+ Report.result(Tests.tags_same_value_equal, tag1.Equal(tag2))
+
+ # Test 2: Verify that two tags with different values are not equal
+ tag2.SetTag('not_equal_test')
+ Report.result(Tests.tags_different_value_unequal, not tag1.Equal(tag2))
-test = TestSurfaceMaskFilter_BasicSurfaceTagCreation()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SurfaceMaskFilter_BasicSurfaceTagCreation)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py
index 1ce7962e6a..6438124698 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py
@@ -4,147 +4,141 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C2561342: Exclusive Surface Masks tags function
-"""
-import os
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.areasystem as areasystem
-import azlmbr.bus as bus
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-import azlmbr.shape as shape
-import azlmbr.surface_data as surface_data
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ default_exclusion_weight = (
+ "Found the expected number of instances with Exclusion Weight set to defaults",
+ "Found an unexpected number of instances with Exclusion Weight set to defaults"
+ )
+ exclusion_weight_below_one = (
+ "Found the expected number of instances with Exclusion Weight set below 1",
+ "Found an unexpected number of instances with Exclusion Weight set below 1"
+ )
-class TestExclusiveSurfaceMasksTag(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_ExclusionList", args=["level"])
+def SurfaceMaskFilter_ExclusionList():
+ """
+ Summary:
+ New level is created and set up with surface shapes with varying surface tags. A simple vegetation area has been
+ created and Vegetation Surface Mask Filter component is added to entity with terrain hole exclusion tag.
- def run_test(self):
- """
- Summary:
- New level is created and set up with surface shapes with varying surface tags. A simple vegetation area has been
- created and Vegetation Surface Mask Filter component is added to entity with terrain hole exclusion tag.
+ Expected Behavior:
+ With default Exclusion settings, vegetation does not plant over the terrain holes.
+ With Exclusion Weight Max below 1.0, vegetation plants over the terrain holes.
- Expected Behavior:
- With default Exclusion settings, vegetation does not plant over the terrain holes.
- With Exclusion Weight Max below 1.0, vegetation plants over the terrain holes.
+ Test Steps:
+ 1) Open an existing level
+ 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ 3) Add a Vegetation Surface Mask Filter component to the entity.
+ 4) Create 2 surface entities to represent terrain and terrain hole surfaces
+ 5) Add an Exclusion List tag to the component, and set it to terrainHole.
+ 6) Check spawn count with default Exclusion Weights
+ 7) Check spawn count with Exclusion Weight Max set below 1.0
- Test Steps:
- 1) Create a new level.
- 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- 3) Add a Vegetation Surface Mask Filter component to the entity.
- 4) Create 2 surface entities to represent terrain and terrain hole surfaces
- 5) Add an Exclusion List tag to the component, and set it to terrainHole.
- 6) Check spawn count with default Exclusion Weights
- 7) Check spawn count with Exclusion Weight Max set below 1.0
-
- Note:
- - 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:
+ - 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 update_surface_tag_exclusion_list(Entity, component_index, surface_tag):
- tag_list = [surface_data.SurfaceTag()]
+ import os
- # assign list with one surface tag to exclusion list
- hydra.get_set_test(Entity, component_index, "Configuration|Exclusion|Surface Tags", tag_list)
+ import azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+ import azlmbr.surface_data as surface_data
- # set that one surface tag element to required surface tag
- component = Entity.components[component_index]
- path = "Configuration|Exclusion|Surface Tags|[0]|Surface Tag"
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
- new_value = hydra.get_component_property_value(component, path)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- if new_value == surface_tag:
- self.log(f"Exclusive surface mask filter of {surface_tag} is added successfully")
- else:
- self.log(f"Failed to add an Exclusive surface mask filter of {surface_tag}")
+ def update_surface_tag_exclusion_list(Entity, component_index, surface_tag):
+ tag_list = [surface_data.SurfaceTag()]
- def update_generated_surface_tag(Entity, component_index, surface_tag):
- tag_list = [surface_data.SurfaceTag()]
+ # assign list with one surface tag to exclusion list
+ hydra.get_set_test(Entity, component_index, "Configuration|Exclusion|Surface Tags", tag_list)
- # assign list with one surface tag to Generated Tags list
- hydra.get_set_test(Entity, component_index, "Configuration|Generated Tags", tag_list)
+ # set that one surface tag element to required surface tag
+ component = Entity.components[component_index]
+ path = "Configuration|Exclusion|Surface Tags|[0]|Surface Tag"
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
+ new_value = hydra.get_component_property_value(component, path)
- # set that one surface tag element to required surface tag
- component = Entity.components[component_index]
- path = "Configuration|Generated Tags|[0]|Surface Tag"
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
- new_value = hydra.get_component_property_value(component, path)
+ if new_value == surface_tag:
+ Report.info(f"Exclusive surface mask filter of {surface_tag} is added successfully")
+ else:
+ Report.info(f"Failed to add an Exclusive surface mask filter of {surface_tag}")
- if new_value == surface_tag:
- self.log(f"Generated surface tag of {surface_tag} is added successfully")
- else:
- self.log(f"Failed to add Generated surface tag of {surface_tag}")
+ def update_generated_surface_tag(Entity, component_index, surface_tag):
+ tag_list = [surface_data.SurfaceTag()]
- # 1) Create a new 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,
- )
+ # assign list with one surface tag to Generated Tags list
+ hydra.get_set_test(Entity, component_index, "Configuration|Generated Tags", tag_list)
- general.set_current_view_position(512.0, 480.0, 38.0)
+ # set that one surface tag element to required surface tag
+ component = Entity.components[component_index]
+ path = "Configuration|Generated Tags|[0]|Surface Tag"
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
+ new_value = hydra.get_component_property_value(component, path)
- # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
- entity_position,
- 10.0, 10.0, 10.0,
- asset_path)
+ if new_value == surface_tag:
+ Report.info(f"Generated surface tag of {surface_tag} is added successfully")
+ else:
+ Report.info(f"Failed to add Generated surface tag of {surface_tag}")
- # 3) Add a Vegetation Surface Mask Filter component to the entity.
- spawner_entity.add_component("Vegetation Surface Mask Filter")
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # 4) Create 2 surface entities to represent terrain and terrain hole surfaces
- surface_tags: dict = {"terrainHole": 1327698037, "terrain": 3363197873}
- entity_position = math.Vector3(510.0, 512.0, 32.0)
- surface_entity_1 = dynveg.create_surface_entity("Surface Entity 1",
- entity_position,
- 10.0, 10.0, 1.0)
- update_generated_surface_tag(surface_entity_1, 1, surface_tags["terrainHole"])
+ general.set_current_view_position(512.0, 480.0, 38.0)
- entity_position = math.Vector3(520.0, 512.0, 32.0)
- surface_entity_2 = dynveg.create_surface_entity("Surface Entity 2",
- entity_position,
- 10.0, 10.0, 1.0)
- update_generated_surface_tag(surface_entity_2, 1, surface_tags["terrain"])
+ # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
+ entity_position,
+ 10.0, 10.0, 10.0,
+ asset_path)
- # 5) Add an Exclusion List tag to the component, and set it to "terrainHole".
- update_surface_tag_exclusion_list(spawner_entity, 3, surface_tags["terrainHole"])
+ # 3) Add a Vegetation Surface Mask Filter component to the entity.
+ spawner_entity.add_component("Vegetation Surface Mask Filter")
- # 6) Check spawn count with default Exclusion Weights
- general.idle_wait(2.0) # Allow a few seconds for instances to spawn
- num_expected_instances = 39
- box = shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- num_found = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
- self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
- self.test_success = self.test_success and num_found == num_expected_instances
+ # 4) Create 2 surface entities to represent terrain and terrain hole surfaces
+ surface_tags: dict = {"terrainHole": 1327698037, "terrain": 3363197873}
+ entity_position = math.Vector3(510.0, 512.0, 32.0)
+ surface_entity_1 = dynveg.create_surface_entity("Surface Entity 1",
+ entity_position,
+ 10.0, 10.0, 1.0)
+ update_generated_surface_tag(surface_entity_1, 1, surface_tags["terrainHole"])
- # 7) Check spawn count with Exclusion Weight Max set below 1.0
- hydra.get_set_test(spawner_entity, 3, "Configuration|Exclusion|Weight Max", 0.9)
- general.idle_wait(2.0) # Allow a few seconds for instances to spawn
- num_expected_instances = 169
- num_found = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
- self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
- self.test_success = self.test_success and num_found == num_expected_instances
+ entity_position = math.Vector3(520.0, 512.0, 32.0)
+ surface_entity_2 = dynveg.create_surface_entity("Surface Entity 2",
+ entity_position,
+ 10.0, 10.0, 1.0)
+ update_generated_surface_tag(surface_entity_2, 1, surface_tags["terrain"])
+
+ # 5) Add an Exclusion List tag to the component, and set it to "terrainHole".
+ update_surface_tag_exclusion_list(spawner_entity, 3, surface_tags["terrainHole"])
+
+ # 6) Check spawn count with default Exclusion Weights
+ num_expected_instances = 39
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected_instances), 2.0)
+ Report.result(Tests.default_exclusion_weight, success)
+
+ # 7) Check spawn count with Exclusion Weight Max set below 1.0
+ hydra.get_set_test(spawner_entity, 3, "Configuration|Exclusion|Weight Max", 0.9)
+ num_expected_instances = 169
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected_instances), 2.0)
+ Report.result(Tests.exclusion_weight_below_one, success)
-test = TestExclusiveSurfaceMasksTag()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SurfaceMaskFilter_ExclusionList)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py
index e394bc0cde..bbd1235abc 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py
@@ -4,148 +4,142 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-C2561341: Inclusive Surface Masks tags function
-"""
-import os
-import sys
-
-sys.path.append(os.path.dirname(os.path.abspath(__file__)))
-import azlmbr.areasystem as areasystem
-import azlmbr.bus as bus
-import azlmbr.editor as editor
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-import azlmbr.shape as shape
-import azlmbr.surface_data as surface_data
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ default_inclusion_weight = (
+ "Found the expected number of instances with Inclusion Weight set to defaults",
+ "Found an unexpected number of instances with Inclusion Weight set to defaults"
+ )
+ inclusion_weight_below_one = (
+ "Found the expected number of instances with Inclusion Weight set below 1",
+ "Found an unexpected number of instances with Inclusion Weight set below 1"
+ )
-class TestInclusiveSurfaceMasksTag(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SurfaceMaskFilter_InclusionList", args=["level"])
- def run_test(self):
- """
- Summary:
- New level is created and set up with surface shapes with varying surface tags. A simple vegetation area has been
- created and Vegetation Surface Mask Filter component is added to entity with terrain hole inclusion tag.
+def SurfaceMaskFilter_InclusionList():
+ """
+ Summary:
+ New level is created and set up with surface shapes with varying surface tags. A simple vegetation area has been
+ created and Vegetation Surface Mask Filter component is added to entity with terrain hole inclusion tag.
- Expected Behavior:
- With default Inclusion Weights, vegetation draws over the terrain holes.
- With Inclusion Weight Max set below 1.0, vegetation stops drawing over the terrain holes.
+ Expected Behavior:
+ With default Inclusion Weights, vegetation draws over the terrain holes.
+ With Inclusion Weight Max set below 1.0, vegetation stops drawing over the terrain holes.
- Test Steps:
- 1) Create a new level
- 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- 3) Add a Vegetation Surface Mask Filter component to the entity.
- 4) Create 2 surface entities to represent terrain and terrain hole surfaces
- 5) Add an Inclusion List tag to the component, and set it to "terrainHole".
- 6) Check spawn count with default Inclusion Weights
- 7) Check spawn count with Inclusion Weight Max set below 1.0
-
- Note:
- - 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) Open an existing level
+ 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ 3) Add a Vegetation Surface Mask Filter component to the entity.
+ 4) Create 2 surface entities to represent terrain and terrain hole surfaces
+ 5) Add an Inclusion List tag to the component, and set it to "terrainHole".
+ 6) Check spawn count with default Inclusion Weights
+ 7) Check spawn count with Inclusion Weight Max set below 1.0
- :return: None
- """
+ Note:
+ - 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 update_surface_tag_inclusion_list(Entity, component_index, surface_tag):
- tag_list = [surface_data.SurfaceTag()]
+ :return: None
+ """
- # assign list with one surface tag to inclusion list
- hydra.get_set_test(Entity, component_index, "Configuration|Inclusion|Surface Tags", tag_list)
+ import os
- # set that one surface tag element to required surface tag
- component = Entity.components[component_index]
- path = "Configuration|Inclusion|Surface Tags|[0]|Surface Tag"
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
- new_value = hydra.get_component_property_value(component, path)
+ import azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+ import azlmbr.surface_data as surface_data
- if new_value == surface_tag:
- print("Inclusive surface mask filter of terrainHole is added successfully")
- else:
- print("Failed to add an Inclusive surface mask filter of terrainHole")
- general.idle_wait(2.0)
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- def update_generated_surface_tag(Entity, component_index, surface_tag):
- tag_list = [surface_data.SurfaceTag()]
+ def update_surface_tag_inclusion_list(Entity, component_index, surface_tag):
+ tag_list = [surface_data.SurfaceTag()]
- # assign list with one surface tag to Generated Tags list
- hydra.get_set_test(Entity, component_index, "Configuration|Generated Tags", tag_list)
+ # assign list with one surface tag to inclusion list
+ hydra.get_set_test(Entity, component_index, "Configuration|Inclusion|Surface Tags", tag_list)
- # set that one surface tag element to required surface tag
- component = Entity.components[component_index]
- path = "Configuration|Generated Tags|[0]|Surface Tag"
- editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
- new_value = hydra.get_component_property_value(component, path)
+ # set that one surface tag element to required surface tag
+ component = Entity.components[component_index]
+ path = "Configuration|Inclusion|Surface Tags|[0]|Surface Tag"
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
+ new_value = hydra.get_component_property_value(component, path)
- if new_value == surface_tag:
- self.log(f"Generated surface tag of {surface_tag} is added successfully")
- else:
- self.log(f"Failed to add Generated surface tag of {surface_tag}")
+ if new_value == surface_tag:
+ Report.info("Inclusive surface mask filter of terrainHole is added successfully")
+ else:
+ Report.info("Failed to add an Inclusive surface mask filter of terrainHole")
- # 1) Create a new 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 update_generated_surface_tag(Entity, component_index, surface_tag):
+ tag_list = [surface_data.SurfaceTag()]
- general.set_current_view_position(512.0, 480.0, 38.0)
+ # assign list with one surface tag to Generated Tags list
+ hydra.get_set_test(Entity, component_index, "Configuration|Generated Tags", tag_list)
- # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
- entity_position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
- entity_position,
- 10.0, 10.0, 10.0,
- asset_path)
+ # set that one surface tag element to required surface tag
+ component = Entity.components[component_index]
+ path = "Configuration|Generated Tags|[0]|Surface Tag"
+ editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", component, path, surface_tag)
+ new_value = hydra.get_component_property_value(component, path)
- # 3) Add a Vegetation Surface Mask Filter component to the entity.
- spawner_entity.add_component("Vegetation Surface Mask Filter")
+ if new_value == surface_tag:
+ Report.info(f"Generated surface tag of {surface_tag} is added successfully")
+ else:
+ Report.info(f"Failed to add Generated surface tag of {surface_tag}")
- # 4) Create 2 surface entities to represent terrain and terrain hole surfaces
- surface_tags: dict = {"terrainHole": 1327698037, "terrain": 3363197873}
- entity_position = math.Vector3(510.0, 512.0, 32.0)
- surface_entity_1 = dynveg.create_surface_entity("Surface Entity 1",
- entity_position,
- 10.0, 10.0, 1.0)
- update_generated_surface_tag(surface_entity_1, 1, surface_tags["terrainHole"])
+ # 1) Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- entity_position = math.Vector3(520.0, 512.0, 32.0)
- surface_entity_2 = dynveg.create_surface_entity("Surface Entity 2",
- entity_position,
- 10.0, 10.0, 1.0)
- update_generated_surface_tag(surface_entity_2, 1, surface_tags["terrain"])
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # 5) Add an Inclusion List tag to the component, and set it to "terrainHole".
- update_surface_tag_inclusion_list(spawner_entity, 3, surface_tags["terrainHole"])
+ # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape"
+ entity_position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Instance Spawner",
+ entity_position,
+ 10.0, 10.0, 10.0,
+ asset_path)
- # 6) Check spawn count with default Inclusion Weights
- general.idle_wait(2.0) # Allow a few seconds for instances to spawn
- num_expected_instances = 130
- box = shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
- num_found = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
- self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
- self.test_success = self.test_success and num_found == num_expected_instances
+ # 3) Add a Vegetation Surface Mask Filter component to the entity.
+ spawner_entity.add_component("Vegetation Surface Mask Filter")
- # 7) Check spawn count with Inclusion Weight Max set below 1.0
- hydra.get_set_test(spawner_entity, 3, "Configuration|Inclusion|Weight Max", 0.9)
- general.idle_wait(2.0) # Allow a few seconds for instances to update
- num_expected_instances = 0
- num_found = areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
- self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
- self.test_success = self.test_success and num_found == num_expected_instances
+ # 4) Create 2 surface entities to represent terrain and terrain hole surfaces
+ surface_tags: dict = {"terrainHole": 1327698037, "terrain": 3363197873}
+ entity_position = math.Vector3(510.0, 512.0, 32.0)
+ surface_entity_1 = dynveg.create_surface_entity("Surface Entity 1",
+ entity_position,
+ 10.0, 10.0, 1.0)
+ update_generated_surface_tag(surface_entity_1, 1, surface_tags["terrainHole"])
+
+ entity_position = math.Vector3(520.0, 512.0, 32.0)
+ surface_entity_2 = dynveg.create_surface_entity("Surface Entity 2",
+ entity_position,
+ 10.0, 10.0, 1.0)
+ update_generated_surface_tag(surface_entity_2, 1, surface_tags["terrain"])
+
+ # 5) Add an Inclusion List tag to the component, and set it to "terrainHole".
+ update_surface_tag_inclusion_list(spawner_entity, 3, surface_tags["terrainHole"])
+
+ # 6) Check spawn count with default Inclusion Weights
+ num_expected_instances = 130
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected_instances), 2.0)
+ Report.result(Tests.default_inclusion_weight, success)
+
+ # 7) Check spawn count with Inclusion Weight Max set below 1.0
+ hydra.get_set_test(spawner_entity, 3, "Configuration|Inclusion|Weight Max", 0.9)
+ num_expected_instances = 0
+ success = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected_instances), 2.0)
+ Report.result(Tests.inclusion_weight_below_one, success)
-test = TestInclusiveSurfaceMasksTag()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SurfaceMaskFilter_InclusionList)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py
index f690e175de..d808d3f20b 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py
@@ -5,89 +5,90 @@ 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.paths
-import azlmbr.editor as editor
-import azlmbr.bus as bus
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_density_instance_count = (
+ "Found the expected number of instances with default sector density",
+ "Found an unexpected number of instances with default sector density"
+ )
+ configured_density_instance_count = (
+ "Found the expected number of instances with a sector density of 10",
+ "Found an unexpected number of instances with a sector density of 10"
+ )
-class TestSystemSettingsSectorPointDensity(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SystemSettings_SectorPointDensity", args=["level"])
+def SystemSettings_SectorPointDensity():
+ """
+ Summary:
+ Sector Point Density increases/reduces the number of vegetation points within a sector
- def run_test(self):
- """
- Summary:
- Sector Point Density increases/reduces the number of vegetation points within a sector
+ Expected Result:
+ Default value for Sector Point Density is 20.
+ 20 vegetation meshes appear on each side of the established vegetation area with the default value.
+ When altered, the specified number of vegetation meshes along a side of a vegetation area matches the value set
+ in Sector Point Density.
- Expected Result:
- Default value for Sector Point Density is 20.
- 20 vegetation meshes appear on each side of the established vegetation area with the default value.
- When altered, the specified number of vegetation meshes along a side of a vegetation area matches the value set
- in Sector Point Density.
+ :return: None
+ """
- :return: None
- """
+ import os
- INSTANCE_COUNT_BEFORE_DENSITY_CHANGE = 400
- INSTANCE_COUNT_AFTER_DENSITY_CHANGE = 100
+ import azlmbr.math as math
+ import azlmbr.editor as editor
+ import azlmbr.bus as bus
+ import azlmbr.legacy.general as general
- # 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,
- )
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- general.set_current_view_position(512.0, 480.0, 38.0)
+ INSTANCE_COUNT_BEFORE_DENSITY_CHANGE = 400
+ INSTANCE_COUNT_AFTER_DENSITY_CHANGE = 100
- # Create basic vegetation entity
- position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
- dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Count the number of vegetation meshes along one side of the new vegetation area. #
- result = self.wait_for_condition(
- lambda: dynveg.validate_instance_count(position, 8.0, INSTANCE_COUNT_BEFORE_DENSITY_CHANGE), 2.0
- )
- self.log(f"Vegetation instances count equal to expected value before changing sector point density: {result}")
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Add the Vegetation Debugger component to the Level Inspector
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ # Create basic vegetation entity
+ position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
+ dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
- # Change Sector Point Density to 10
- editor.EditorComponentAPIBus(
- bus.Broadcast,
- "SetComponentProperty",
- veg_system_settings_component,
- "Configuration|Area System Settings|Sector Point Snap Mode",
- 1,
- )
- editor.EditorComponentAPIBus(
- bus.Broadcast,
- "SetComponentProperty",
- veg_system_settings_component,
- "Configuration|Area System Settings|Sector Point Density",
- 10,
- )
+ # Count the number of vegetation instances in the vegetation area
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0,
+ INSTANCE_COUNT_BEFORE_DENSITY_CHANGE), 2.0)
+ Report.result(Tests.initial_density_instance_count, result)
- # Count the number of vegetation meshes along one side of the new vegetation area.
- result = self.wait_for_condition(
- lambda: dynveg.validate_instance_count(position, 8.0, INSTANCE_COUNT_AFTER_DENSITY_CHANGE), 2.0
- )
- self.log(f"Vegetation instances count equal to expected value after changing sector point density: {result}")
+ # Add the Vegetation Debugger component to the Level Inspector
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+
+ # Change Sector Point Density to 10
+ editor.EditorComponentAPIBus(
+ bus.Broadcast,
+ "SetComponentProperty",
+ veg_system_settings_component,
+ "Configuration|Area System Settings|Sector Point Snap Mode",
+ 1,
+ )
+ editor.EditorComponentAPIBus(
+ bus.Broadcast,
+ "SetComponentProperty",
+ veg_system_settings_component,
+ "Configuration|Area System Settings|Sector Point Density",
+ 10,
+ )
+
+ # Count the number of vegetation instances in the vegetation area
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 8.0,
+ INSTANCE_COUNT_AFTER_DENSITY_CHANGE), 2.0)
+ Report.result(Tests.configured_density_instance_count, result)
-test = TestSystemSettingsSectorPointDensity()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SystemSettings_SectorPointDensity)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py
index 61aaedcf7c..fb660c964a 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py
@@ -5,88 +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
-import azlmbr.math as math
-import azlmbr.paths
-import azlmbr.editor as editor
-import azlmbr.bus as bus
-import azlmbr.legacy.general as general
-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
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ initial_sector_size_instance_count = (
+ "Found the expected number of instances with default sector size",
+ "Found an unexpected number of instances with default sector size"
+ )
+ configured_sector_size_instance_count = (
+ "Found the expected number of instances with a sector size of 10",
+ "Found an unexpected number of instances with a sector size of 10"
+ )
-class TestSystemSettingsSectorSize(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix="SystemSettings_SectorSize", args=["level"])
+def SystemSettings_SectorSize():
+ """
+ Summary:
+ Sector Size In Meters increases/reduces the size of a sector
- def run_test(self):
- """
- Summary:
- Sector Size In Meters increases/reduces the size of a sector
+ Expected Result:
+ The number of spawned vegetation meshes inside the vegetation area is identical after updating the Sector Size
- Expected Result:
- The number of spawned vegetation meshes inside the vegetation area is identical after updating the Sector Size
+ :return: None
+ """
- :return: None
- """
+ import os
- VEGETATION_INSTANCE_COUNT = 400
+ import azlmbr.math as math
+ import azlmbr.editor as editor
+ import azlmbr.bus as bus
+ import azlmbr.legacy.general as general
- # 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,
- )
+ import editor_python_test_tools.hydra_editor_utils as hydra
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- general.set_current_view_position(512.0, 480.0, 38.0)
+ VEGETATION_INSTANCE_COUNT = 400
- # Create basic vegetation entity
- position = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
- vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
- dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Add the Vegetation Debugger component to the Level Inspector
- veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
+ general.set_current_view_position(512.0, 480.0, 38.0)
- # Count the number of vegetation meshes along one side of the new vegetation area.
- result = self.wait_for_condition(
- lambda: dynveg.validate_instance_count(position, 8.0, VEGETATION_INSTANCE_COUNT), 2.0
- )
- self.log(f"Vegetation instances count equal to expected value before changing sector size: {result}")
+ # Create basic vegetation entity
+ position = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PinkFlower.dynamicslice")
+ vegetation = dynveg.create_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path)
+ dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0)
- # Change Sector Size in Meters to 10.
- editor.EditorComponentAPIBus(
- bus.Broadcast,
- "SetComponentProperty",
- veg_system_settings_component,
- "Configuration|Area System Settings|Sector Point Snap Mode",
- 1,
- )
- editor.EditorComponentAPIBus(
- bus.Broadcast,
- "SetComponentProperty",
- veg_system_settings_component,
- "Configuration|Area System Settings|Sector Size In Meters",
- 10,
- )
+ # Add the Vegetation Debugger component to the Level Inspector
+ veg_system_settings_component = hydra.add_level_component("Vegetation System Settings")
- # Alter the Box Shape to be 10,10,1
- vegetation.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(10.0, 10.0, 1.0))
+ # Count the number of vegetation instances in the vegetation area
+ result = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count(position, 8.0, VEGETATION_INSTANCE_COUNT), 2.0
+ )
+ Report.result(Tests.initial_sector_size_instance_count, result)
- # Count the number of vegetation meshes along one side of the new vegetation area.
- result = self.wait_for_condition(
- lambda: dynveg.validate_instance_count(position, 5.0, VEGETATION_INSTANCE_COUNT), 2.0
- )
- self.log(f"Vegetation instances count equal to expected value after changing sector size: {result}")
+ # Change Sector Size in Meters to 10.
+ editor.EditorComponentAPIBus(
+ bus.Broadcast,
+ "SetComponentProperty",
+ veg_system_settings_component,
+ "Configuration|Area System Settings|Sector Point Snap Mode",
+ 1,
+ )
+ editor.EditorComponentAPIBus(
+ bus.Broadcast,
+ "SetComponentProperty",
+ veg_system_settings_component,
+ "Configuration|Area System Settings|Sector Size In Meters",
+ 10,
+ )
+
+ # Alter the Box Shape to be 10,10,1
+ vegetation.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(10.0, 10.0, 1.0))
+
+ # Count the number of vegetation instances in the vegetation area
+ result = helper.wait_for_condition(
+ lambda: dynveg.validate_instance_count(position, 5.0, VEGETATION_INSTANCE_COUNT), 2.0
+ )
+ Report.result(Tests.configured_sector_size_instance_count, result)
-test = TestSystemSettingsSectorSize()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(SystemSettings_SectorSize)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py
index 6f40d04854..a0657f3949 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py
@@ -5,89 +5,85 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-"""
-This script tests for regressions of "vegetation instances don't despawn correctly
-when the camera moves beyond the range of all active vegetation areas".
-This creates a new level and a vegetation area with 400 instances.
-The expectation is that we will have 400 instances in that area when the camera is centered on it,
-and 0 instances when the camera is moved sufficiently far away.
-"""
-
-import sys, os
-
-import azlmbr.legacy.general as general
-import azlmbr.math as math
-
-sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
-from editor_python_test_tools.editor_test_helper import EditorTestHelper
-from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+class Tests:
+ instance_validation_close = (
+ "Instance count is as expected when within range of Spawner",
+ "Instance count was unexpected when within range of Spawner"
+ )
+ instance_validation_far = (
+ "No instances found when out of range of Spawner",
+ "Instances still found when out of range of Spawner"
+ )
-class TestVegetationInstances_DespawnWhenOutOfRange(EditorTestHelper):
- def __init__(self):
- EditorTestHelper.__init__(self, log_prefix='VegetationInstances_DespawnWhenOutOfRange', args=['level'])
+def VegetationInstances_DespawnWhenOutOfRange():
+ """
+ Summary:
+ Verifies that vegetation instances properly spawn/despawn based on camera range.
- def run_test(self):
- """
- Summary:
- Verifies that vegetation instances properly spawn/despawn based on camera range.
+ Expected Behavior:
+ Vegetation instances despawn when out of camera range.
- Expected Behavior:
- Vegetation instances despawn when out of camera range.
+ Test Steps:
+ 1) Open a simple level
+ 2) Create a simple vegetation area, and set the view position near the spawner. Verify instances plant.
+ 3) Move the view position away from the spawner. Verify instances despawn.
- Test Steps:
- 1) Create a new level
- 2) Create a simple vegetation area, and set the view position near the spawner. Verify instances plant.
- 3) Move the view position away from the spawner. Verify instances despawn.
+ 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 level
- self.test_success = self.create_level(
- self.get_arg('level'),
- heightmap_resolution=128,
- heightmap_meters_per_pixel=1,
- terrain_texture_resolution=128,
- use_terrain=False)
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
- # Create vegetation layer spawner
- world_center = math.Vector3(512.0, 512.0, 32.0)
- asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
- spawner_entity = dynveg.create_vegetation_area("Spawner Instance", world_center, 16.0, 16.0, 16.0, asset_path)
+ from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import TestHelper as helper
- # Create a surface to spawn on
- dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0)
+ # Open an existing simple level
+ helper.init_idle()
+ helper.open_level("Physics", "Base")
- # Get the root position of our veg area and use it to position our camera.
- # This is useful both to ensure that vegetation is spawned where we're querying and to
- # visually verify the number of instances in each box
- position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", spawner_entity.id)
- general.set_current_view_position(position.x, position.y, position.z + 30.0)
- general.set_current_view_rotation(-90.0, 0.0, 0.0)
+ # Create vegetation layer spawner
+ world_center = math.Vector3(512.0, 512.0, 32.0)
+ asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice")
+ spawner_entity = dynveg.create_vegetation_area("Spawner Instance", world_center, 16.0, 16.0, 16.0, asset_path)
- # When centered over the veg area, we expect to find 400 instances.
- # (16x16 area, 20 points per 16 meters)
- num_expected = 400
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 2.0)
- self.test_success = self.test_success and result
+ # Create a surface to spawn on
+ dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0)
- # Move sufficiently far away from the veg area that it should all despawn.
- general.set_current_view_position(position.x - 1000.0, position.y - 1000.0, position.z + 30.0)
+ # Get the root position of our veg area and use it to position our camera.
+ # This is useful both to ensure that vegetation is spawned where we're querying and to
+ # visually verify the number of instances in each box
+ position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", spawner_entity.id)
+ general.set_current_view_position(position.x, position.y, position.z + 30.0)
+ general.set_current_view_rotation(-90.0, 0.0, 0.0)
- # We now expect to find 0 instances. If the bug exists, we will find 400 still.
- num_expected = 0
- result = self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
- num_expected), 2.0)
- self.test_success = self.test_success and result
+ # When centered over the veg area, we expect to find 400 instances.
+ # (16x16 area, 20 points per 16 meters)
+ num_expected = 400
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 2.0)
+ Report.result(Tests.instance_validation_close, result)
+
+ # Move sufficiently far away from the veg area that it should all despawn.
+ general.set_current_view_position(position.x - 1000.0, position.y - 1000.0, position.z + 30.0)
+
+ # We now expect to find 0 instances. If the bug exists, we will find 400 still.
+ num_expected = 0
+ result = helper.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id,
+ num_expected), 2.0)
+ Report.result(Tests.instance_validation_far, result)
-test = TestVegetationInstances_DespawnWhenOutOfRange()
-test.run()
+if __name__ == "__main__":
+
+ from editor_python_test_tools.utils import Report
+ Report.start_test(VegetationInstances_DespawnWhenOutOfRange)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py
new file mode 100644
index 0000000000..4c02c887ef
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py
@@ -0,0 +1,27 @@
+"""
+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_main
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+class TestAutomation(TestAutomationBase):
+
+ def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module
+ self._run_test(request, workspace, editor, test_module)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py
new file mode 100644
index 0000000000..ded2dda4e9
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py
@@ -0,0 +1,172 @@
+"""
+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.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
+@pytest.mark.SUITE_main
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+class TestAutomation(EditorTestSuite):
+
+ class test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(EditorParallelTest):
+ from .EditorScripts import DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks as test_module
+
+ class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorParallelTest):
+ from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module
+
+ class test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(EditorParallelTest):
+ from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module
+
+ class test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(EditorParallelTest):
+ from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module
+
+ class test_AltitudeFilter_FilterStageToggle(EditorParallelTest):
+ from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module
+
+ class test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(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_1.slice")], True, True)
+ file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices",
+ "TestSlice_2.slice")], True, True)
+ from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
+
+ class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorParallelTest):
+ from .EditorScripts import AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea as test_module
+
+ class test_AssetWeightSelector_InstancesExpressBasedOnWeight(EditorParallelTest):
+ from .EditorScripts import AssetWeightSelector_InstancesExpressBasedOnWeight as test_module
+
+ @pytest.mark.skip(reason="https://github.com/o3de/o3de/issues/4155")
+ class test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(EditorParallelTest):
+ from .EditorScripts import DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius as test_module
+
+ @pytest.mark.skip(reason="https://github.com/o3de/o3de/issues/4155")
+ class test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(EditorParallelTest):
+ from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module
+
+ class test_SurfaceDataRefreshes_RemainsStable(EditorParallelTest):
+ from .EditorScripts import SurfaceDataRefreshes_RemainsStable as test_module
+
+ class test_VegetationInstances_DespawnWhenOutOfRange(EditorParallelTest):
+ from .EditorScripts import VegetationInstances_DespawnWhenOutOfRange as test_module
+
+ class test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(EditorParallelTest):
+ from .EditorScripts import InstanceSpawnerPriority_LayerAndSubPriority as test_module
+
+ class test_LayerBlocker_InstancesBlockedInConfiguredArea(EditorParallelTest):
+ from .EditorScripts import LayerBlocker_InstancesBlockedInConfiguredArea as test_module
+
+ class test_LayerSpawner_InheritBehaviorFlag(EditorParallelTest):
+ from .EditorScripts import LayerSpawner_InheritBehaviorFlag as test_module
+
+ class test_LayerSpawner_InstancesPlantInAllSupportedShapes(EditorParallelTest):
+ from .EditorScripts import LayerSpawner_InstancesPlantInAllSupportedShapes as test_module
+
+ class test_LayerSpawner_FilterStageToggle(EditorParallelTest):
+ from .EditorScripts import LayerSpawner_FilterStageToggle as test_module
+
+ @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2038")
+ class test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(EditorParallelTest):
+ from .EditorScripts import LayerSpawner_InstancesRefreshUsingCorrectViewportCamera as test_module
+
+ class test_MeshBlocker_InstancesBlockedByMesh(EditorParallelTest):
+ from .EditorScripts import MeshBlocker_InstancesBlockedByMesh as test_module
+
+ class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorParallelTest):
+ from .EditorScripts import MeshBlocker_InstancesBlockedByMeshHeightTuning as test_module
+
+ class test_MeshSurfaceTagEmitter_DependentOnMeshComponent(EditorParallelTest):
+ from .EditorScripts import MeshSurfaceTagEmitter_DependentOnMeshComponent as test_module
+
+ class test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorParallelTest):
+ from .EditorScripts import MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module
+
+ class test_PhysXColliderSurfaceTagEmitter_E2E_Editor(EditorParallelTest):
+ from .EditorScripts import PhysXColliderSurfaceTagEmitter_E2E_Editor as test_module
+
+ class test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(EditorParallelTest):
+ from .EditorScripts import PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets as test_module
+
+ class test_PositionModifier_AutoSnapToSurfaceWorks(EditorParallelTest):
+ from .EditorScripts import PositionModifier_AutoSnapToSurfaceWorks as test_module
+
+ class test_RotationModifier_InstancesRotateWithinRange(EditorParallelTest):
+ from .EditorScripts import RotationModifier_InstancesRotateWithinRange as test_module
+
+ class test_RotationModifierOverrides_InstancesRotateWithinRange(EditorParallelTest):
+ from .EditorScripts import RotationModifierOverrides_InstancesRotateWithinRange as test_module
+
+ class test_ScaleModifier_InstancesProperlyScale(EditorParallelTest):
+ from .EditorScripts import ScaleModifier_InstancesProperlyScale as test_module
+
+ class test_ScaleModifierOverrides_InstancesProperlyScale(EditorParallelTest):
+ from .EditorScripts import ScaleModifierOverrides_InstancesProperlyScale as test_module
+
+ class test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(EditorParallelTest):
+ from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module
+
+ class test_ShapeIntersectionFilter_FilterStageToggle(EditorParallelTest):
+ from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module
+
+ class test_SlopeAlignmentModifier_InstanceSurfaceAlignment(EditorParallelTest):
+ from .EditorScripts import SlopeAlignmentModifier_InstanceSurfaceAlignment as test_module
+
+ class test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(EditorParallelTest):
+ from .EditorScripts import SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment as test_module
+
+ class test_SurfaceMaskFilter_BasicSurfaceTagCreation(EditorParallelTest):
+ from .EditorScripts import SurfaceMaskFilter_BasicSurfaceTagCreation as test_module
+
+ class test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(EditorParallelTest):
+ from .EditorScripts import SurfaceMaskFilter_ExclusionList as test_module
+
+ class test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(EditorParallelTest):
+ from .EditorScripts import SurfaceMaskFilter_InclusionList as test_module
+
+ class test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(EditorParallelTest):
+ from .EditorScripts import SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected as test_module
+
+ class test_SystemSettings_SectorPointDensity(EditorParallelTest):
+ from .EditorScripts import SystemSettings_SectorPointDensity as test_module
+
+ class test_SystemSettings_SectorSize(EditorParallelTest):
+ from .EditorScripts import SystemSettings_SectorSize as test_module
+
+ class test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(EditorParallelTest):
+ from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module
+
+ class test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(EditorSingleTest):
+ from .EditorScripts import DynamicSliceInstanceSpawner_Embedded_E2E as test_module
+
+ # Custom teardown to remove test level 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", "Levels", "tmp_level")],
+ True, True)
+
+ class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest):
+ from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
+
+ # Custom teardown to remove test level 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", "Levels", "tmp_level")],
+ True, True)
+
+ class test_LayerBlender_E2E_Editor(EditorSingleTest):
+ from .EditorScripts import LayerBlender_E2E_Editor as test_module
+
+ # Custom teardown to remove test level 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", "Levels", "tmp_level")],
+ True, True)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py
new file mode 100644
index 0000000000..2780c0f471
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py
@@ -0,0 +1,283 @@
+"""
+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.waiter as waiter
+import ly_test_tools.environment.file_system as file_system
+import editor_python_test_tools.hydra_test_utils as hydra
+from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole
+
+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_1.slice")], True,
+ True)
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_2.slice")], True,
+ True)
+
+ def teardown():
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_1.slice")], True,
+ True)
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_2.slice")], True,
+ True)
+ request.addfinalizer(teardown)
+
+
+@pytest.fixture
+def remote_console_instance(request):
+ console = RemoteConsole()
+
+ def teardown():
+ if console.connected:
+ console.stop()
+
+ request.addfinalizer(teardown)
+ return console
+
+
+@pytest.mark.SUITE_periodic
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+class TestAutomation(TestAutomationBase):
+
+ def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_AltitudeFilter_FilterStageToggle(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(self, request, workspace, editor, remove_test_slice, launcher_platform):
+ from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_AssetWeightSelector_InstancesExpressBasedOnWeight(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import AssetWeightSelector_InstancesExpressBasedOnWeight as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155")
+ def test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155")
+ def test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SurfaceDataRefreshes_RemainsStable(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SurfaceDataRefreshes_RemainsStable as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_VegetationInstances_DespawnWhenOutOfRange(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import VegetationInstances_DespawnWhenOutOfRange as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import InstanceSpawnerPriority_LayerAndSubPriority as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_LayerBlocker_InstancesBlockedInConfiguredArea(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import LayerBlocker_InstancesBlockedInConfiguredArea as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_LayerSpawner_InheritBehaviorFlag(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import LayerSpawner_InheritBehaviorFlag as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_LayerSpawner_InstancesPlantInAllSupportedShapes(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import LayerSpawner_InstancesPlantInAllSupportedShapes as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_LayerSpawner_FilterStageToggle(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import LayerSpawner_FilterStageToggle as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2038")
+ def test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import LayerSpawner_InstancesRefreshUsingCorrectViewportCamera as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_MeshBlocker_InstancesBlockedByMesh(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import MeshBlocker_InstancesBlockedByMesh as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_MeshBlocker_InstancesBlockedByMeshHeightTuning(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import MeshBlocker_InstancesBlockedByMeshHeightTuning as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_MeshSurfaceTagEmitter_DependentOnMeshComponent(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import MeshSurfaceTagEmitter_DependentOnMeshComponent as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_PhysXColliderSurfaceTagEmitter_E2E_Editor(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import PhysXColliderSurfaceTagEmitter_E2E_Editor as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_PositionModifier_AutoSnapToSurfaceWorks(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import PositionModifier_AutoSnapToSurfaceWorks as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_RotationModifier_InstancesRotateWithinRange(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import RotationModifier_InstancesRotateWithinRange as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_RotationModifierOverrides_InstancesRotateWithinRange(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import RotationModifierOverrides_InstancesRotateWithinRange as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_ScaleModifier_InstancesProperlyScale(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import ScaleModifier_InstancesProperlyScale as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_ScaleModifierOverrides_InstancesProperlyScale(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import ScaleModifierOverrides_InstancesProperlyScale as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_ShapeIntersectionFilter_FilterStageToggle(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SlopeAlignmentModifier_InstanceSurfaceAlignment(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SlopeAlignmentModifier_InstanceSurfaceAlignment as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SurfaceMaskFilter_BasicSurfaceTagCreation(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SurfaceMaskFilter_BasicSurfaceTagCreation as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SurfaceMaskFilter_ExclusionList as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SurfaceMaskFilter_InclusionList as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SystemSettings_SectorPointDensity(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SystemSettings_SectorPointDensity as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SystemSettings_SectorSize(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SystemSettings_SectorSize as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ def test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(self, request, workspace, editor, launcher_platform):
+ from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+
+@pytest.mark.SUITE_periodic
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("level", ["tmp_level"])
+class TestAutomationE2E(TestAutomationBase):
+
+ # The following tests must run in order, please do not move tests out of order
+
+ @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+ def test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(self, request, workspace, project, level, editor, launcher_platform):
+ # Ensure our test level does not already exist
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
+
+ from .EditorScripts import DynamicSliceInstanceSpawner_Embedded_E2E as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ @pytest.mark.parametrize("launcher_platform", ['windows'])
+ def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level,
+ remote_console_instance, project, launcher_platform):
+
+ expected_lines = [
+ "Instances found in area = 400"
+ ]
+
+ hydra.launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines, launch_ap=False)
+
+ # Cleanup our temp level
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
+
+ @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+ def test_DynamicSliceInstanceSpawner_External_E2E_Editor(self, request, workspace, project, level, editor, launcher_platform):
+ # Ensure our test level does not already exist
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
+
+ from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ @pytest.mark.parametrize("launcher_platform", ['windows'])
+ def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level,
+ remote_console_instance, project, launcher_platform):
+
+ expected_lines = [
+ "Instances found in area = 400"
+ ]
+
+ hydra.launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines, launch_ap=False)
+
+ # Cleanup our temp level
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
+
+ @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+ def test_LayerBlender_E2E_Editor(self, request, workspace, project, level, editor, launcher_platform):
+ # Ensure our test level does not already exist
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
+
+ from .EditorScripts import LayerBlender_E2E_Editor as test_module
+ self._run_test(request, workspace, editor, test_module)
+
+ @pytest.mark.parametrize("launcher_platform", ['windows'])
+ @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4170")
+ def test_LayerBlender_E2E_Launcher(self, workspace, launcher, level,
+ remote_console_instance, project, launcher_platform):
+
+ launcher.args.extend(["-rhi=Null"])
+ launcher.start(launch_ap=False)
+ assert launcher.is_alive(), "Launcher failed to start"
+
+ # Wait for test script to quit the launcher. If wait_for returns exc, test was not successful
+ waiter.wait_for(lambda: not launcher.is_alive(), timeout=300)
+
+ # Verify launcher quit successfully and did not crash
+ ret_code = launcher.get_returncode()
+ assert ret_code == 0, "Test failed. See Game.log for details"
+
+ # Cleanup our temp level
+ file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AltitudeFilter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AltitudeFilter.py
deleted file mode 100755
index ec8c225d3b..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AltitudeFilter.py
+++ /dev/null
@@ -1,111 +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 pytest
-import logging
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestAltitudeFilter(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id('C4814463', 'C4847477')
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Planting Surface' created",
- "'Planting Surface Elevated' created",
- "instance count validation: True (found=3200, expected=3200)",
- "instance count validation: True (found=1600, expected=1600)",
- "instance count validation: True (found=400, expected=400)",
- "AltitudeFilterComponentAndOverrides: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4847476")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Planting Surface' created",
- "'Planting Surface Elevated' created",
- "instance count validation: True (found=800, expected=800)",
- "'Shape Sampler' created",
- "instance count validation: True (found=400, expected=400)",
- "AltitudeFilterShapeSample: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4847478")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2303")
- def test_AltitudeFilter_FilterStageToggle(self, request, editor, level, workspace, launcher_platform):
- cfg_args = [level]
-
- expected_lines = [
- "AltitudeFilter_FilterStageToggle: test started",
- "AltitudeFilter_FilterStageToggle: Vegetation instances count equal to expected value for PREPROCESS filter stage: True",
- "AltitudeFilter_FilterStageToggle: Vegetation instances count equal to expected value for POSTPROCESS filter stage: True",
- "AltitudeFilter_FilterStageToggle: result=SUCCESS",
- ]
-
- unexpected_lines = [
- "AltitudeFilter_FilterStageToggle: Vegetation instances count equal to expected value for PREPROCESS filter stage: False",
- "AltitudeFilter_FilterStageToggle: Vegetation instances count equal to expected value for POSTPROCESS filter stage: False",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "AltitudeFilter_FilterStageToggle.py",
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- cfg_args=cfg_args
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AreaComponentSlices.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AreaComponentSlices.py
deleted file mode 100755
index 7c72105957..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AreaComponentSlices.py
+++ /dev/null
@@ -1,72 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestAreaComponents(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Cleanup the test slices
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_1.slice")], True, True)
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_2.slice")], True, True)
-
- def teardown():
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Cleanup the test slices
- file_system.delete(
- [os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_1.slice")], True, True
- )
- file_system.delete(
- [os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_2.slice")], True, True
- )
-
- request.addfinalizer(teardown)
-
- @pytest.mark.test_case_id("C2627900", "C2627905", "C2627904")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_AreaComponents_SliceCreationVisibilityToggleWorks(self, request, editor, level, workspace,
- launcher_platform):
- cfg_args = [level]
-
- expected_lines = [
- "AreaComponentSlices_SliceCreationAndVisibilityToggle: test started",
- "AreaComponentSlices_SliceCreationAndVisibilityToggle: Slice has been created successfully (entity with spawner component): True",
- "AreaComponentSlices_SliceCreationAndVisibilityToggle: Vegetation plants initially when slice is shown: True",
- "AreaComponentSlices_SliceCreationAndVisibilityToggle: Vegetation is cleared when slice is hidden: True",
- "AreaComponentSlices_SliceCreationAndVisibilityToggle: Slice has been created successfully (entity with blender component): True",
- "AreaComponentSlices_SliceCreationAndVisibilityToggle: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "AreaComponentSlices_SliceCreationAndVisibilityToggle.py",
- expected_lines=expected_lines,
- cfg_args=cfg_args
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AssetListCombiner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AssetListCombiner.py
deleted file mode 100755
index 5deaa9199e..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AssetListCombiner.py
+++ /dev/null
@@ -1,63 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize('project', ['AutomatedTesting'])
-@pytest.mark.parametrize('level', ['tmp_level'])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestAssetListCombiner(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4762374", "C4762373")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Asset List 1' created",
- "'Asset List 2' created",
- "'Asset List 3' created",
- "'Surface Entity' created",
- "'Spawner Entity' created",
- "Spawner Entity Configuration|Descriptor Providers: SUCCESS",
- "Spawner Entity Configuration|Gradient|Gradient Entity Id: SUCCESS",
- "instance count validation: True (found=200, expected=200.0)",
- "Spawner Entity Configuration|Descriptor Providers|[1]: SUCCESS",
- "instance count validation: True (found=400, expected=400)",
- "instance count validation: True (found=0, expected=0)",
- "AssetListCombiner_CombinedDescriptors: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py",
- expected_lines=expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AssetWeightSelector.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AssetWeightSelector.py
deleted file mode 100755
index f3cb2f4647..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_AssetWeightSelector.py
+++ /dev/null
@@ -1,60 +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
-"""
-
-"""
-C6269654: Vegetation areas using weight selectors properly distribute instances according to Sort By Weight setting
-"""
-
-import os
-import pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestAssetWeightSelector(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C6269654", "C4762368")
- @pytest.mark.SUITE_sandbox
- @pytest.mark.dynveg_filter
- def test_AssetWeightSelector_InstancesExpressBasedOnWeight(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "Instance Spawner Configuration|Embedded Assets|[1]|Instance|Slice Asset: SUCCESS",
- "'Planting Surface' created",
- "Configuration|Embedded Assets|[0]|Weight set to 50.0",
- "Instance Spawner Configuration|Allow Empty Assets: SUCCESS",
- "AssetWeightSelector_SortByWeight: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "AssetWeightSelector_InstancesExpressBasedOnWeight.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DistanceBetweenFilter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DistanceBetweenFilter.py
deleted file mode 100755
index 6d1b688315..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DistanceBetweenFilter.py
+++ /dev/null
@@ -1,76 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestDistanceBetweenFilter(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4851066")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "Configuration|Radius Min set to 1.0",
- "Configuration|Radius Min set to 2.0",
- "Configuration|Radius Min set to 16.0",
- "DistanceBetweenFilterComponent: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4814458")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min set to 1.0",
- "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min set to 2.0",
- "Configuration|Embedded Assets|[0]|Distance Between Filter (Radius)|Radius Min set to 16.0",
- "DistanceBetweenFilterComponentOverrides: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynVeg_Regressions.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynVeg_Regressions.py
deleted file mode 100755
index b15e1d552d..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynVeg_Regressions.py
+++ /dev/null
@@ -1,78 +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 pytest
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-
-import editor_python_test_tools.hydra_test_utils as hydra
-import ly_test_tools.environment.file_system as file_system
-
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize('project', ['AutomatedTesting'])
-@pytest.mark.parametrize('level', ['tmp_level'])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class Test_DynVeg_Regressions(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- # delete temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Setup - add the teardown finalizer
- request.addfinalizer(teardown)
-
- # Make sure the temp level doesn't already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C29470845")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_regression
- def test_SurfaceDataRefreshes_RemainsStable(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "SurfaceDataRefreshes_RemainsStable: test started",
- "SurfaceDataRefreshes_RemainsStable: test finished",
- "SurfaceDataRefreshes_RemainsStable: result=SUCCESS"
- ]
-
- unexpected_lines = [
- "Sector update mode is 'RebuildSurfaceCache' but sector doesn't exist"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- 'SurfaceDataRefreshes_RemainsStable.py',
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.SUITE_periodic
- def test_VegetationInstances_DespawnWhenOutOfRange(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "VegetationInstances_DespawnWhenOutOfRange: test started",
- "VegetationInstances_DespawnWhenOutOfRange: test finished",
- "VegetationInstances_DespawnWhenOutOfRange: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- 'VegetationInstances_DespawnWhenOutOfRange.py',
- expected_lines=expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py
deleted file mode 100755
index 0f83f44094..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_DynamicSliceInstanceSpawner.py
+++ /dev/null
@@ -1,140 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import ly_test_tools._internal.pytest_plugin as internal_plugin
-import editor_python_test_tools.hydra_test_utils as hydra
-from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize('project', ['AutomatedTesting'])
-@pytest.mark.parametrize('level', ['tmp_level'])
-@pytest.mark.usefixtures("automatic_process_killer")
-class TestDynamicSliceInstanceSpawner(object):
-
- @pytest.fixture
- def remote_console_instance(self, request):
- console = RemoteConsole()
-
- def teardown():
- if console.connected:
- console.stop()
-
- request.addfinalizer(teardown)
-
- return console
-
- @pytest.mark.test_case_id("C28851763")
- @pytest.mark.SUITE_main
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
- def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, editor, level, workspace, project,
- launcher_platform):
-
- # Skip test if running against Debug build
- if "debug" in internal_plugin.build_directory:
- pytest.skip("Does not execute against debug builds.")
-
- # Ensure temp level does not already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- cfg_args = [level]
-
- expected_lines = [
- "DynamicSliceInstanceSpawner: test started",
- "DynamicSliceInstanceSpawner: test finished",
- "DynamicSliceInstanceSpawner: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(request, test_directory, editor,
- 'DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py',
- expected_lines=expected_lines, cfg_args=cfg_args)
-
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id('C2574330')
- @pytest.mark.BAT
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
- def test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(self, workspace, request, editor, level, project,
- launcher_platform):
- # Ensure temp level does not already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Planting Surface' created",
- "DynamicSliceInstanceSpawnerEmbeddedEditor: Expected 400 instances - Found 400 instances",
- "DynamicSliceInstanceSpawnerEmbeddedEditor: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(request, test_directory, editor, "DynamicSliceInstanceSpawner_Embedded_E2E.py",
- expected_lines, cfg_args=[level])
-
- @pytest.mark.test_case_id('C2574330')
- @pytest.mark.BAT
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows'])
- def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level,
- remote_console_instance, project, launcher_platform):
-
- expected_lines = [
- "Instances found in area = 400"
- ]
-
- hydra.launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines)
-
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id('C4762367')
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
- def test_DynamicSliceInstanceSpawner_External_E2E_Editor(self, workspace, request, editor, level, project,
- launcher_platform):
- # Ensure temp level does not already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- expected_lines = [
- "Spawner entity created",
- "'Planting Surface' created",
- "DynamicSliceInstanceSpawnerExternalEditor: Expected 400 instances - Found 400 instances",
- "DynamicSliceInstanceSpawnerExternalEditor: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(request, test_directory, editor, "DynamicSliceInstanceSpawner_External_E2E.py",
- expected_lines, cfg_args=[level])
-
- @pytest.mark.test_case_id('C4762367')
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows'])
- def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level,
- remote_console_instance, project, launcher_platform):
-
- expected_lines = [
- "Instances found in area = 400"
- ]
-
- hydra.launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines)
-
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py
deleted file mode 100755
index 1fc88b816f..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_EmptyInstanceSpawner.py
+++ /dev/null
@@ -1,54 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import ly_test_tools._internal.pytest_plugin as internal_plugin
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize('project', ['AutomatedTesting'])
-@pytest.mark.parametrize('level', ['tmp_level'])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestEmptyInstanceSpawner(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C28851762")
- @pytest.mark.SUITE_main
- @pytest.mark.dynveg_area
- def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, editor, level, launcher_platform):
-
- # Skip test if running against Debug build
- if "debug" in internal_plugin.build_directory:
- pytest.skip("Does not execute against debug builds.")
-
- cfg_args = [level]
-
- expected_lines = [
- "EmptyInstanceSpawner: test started",
- "EmptyInstanceSpawner: test finished",
- "EmptyInstanceSpawner: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(request, test_directory, editor, 'EmptyInstanceSpawner_EmptySpawnerWorks.py',
- expected_lines=expected_lines, cfg_args=cfg_args)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_InstanceSpawnerPriority.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_InstanceSpawnerPriority.py
deleted file mode 100755
index 955c20a37d..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_InstanceSpawnerPriority.py
+++ /dev/null
@@ -1,63 +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
-"""
-
-"""
-C5747383: Vegetation areas with a higher Layer Priority plant over those with a lower Layer Priority
-C4762382: Vegetation areas with a higher Sub Priority plant over those with a lower Sub Priority
-"""
-
-import os
-import pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestInstanceSpawnerPriority(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C5747383", "C4762382")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Instance Blocker' created",
- "'Planting Surface' created",
- "Instance Blocker Configuration|Layer Priority: SUCCESS",
- "Instance Spawner Configuration|Sub Priority: SUCCESS",
- "Instance Blocker Configuration|Sub Priority: SUCCESS",
- "InstanceSpawnerPriority: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "InstanceSpawnerPriority_LayerAndSubPriority.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py
deleted file mode 100755
index 13f2a569c1..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlender.py
+++ /dev/null
@@ -1,104 +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
-"""
-
-"""
-C2627906: A simple Vegetation Layer Blender area can be created.
-The specified assets plant in the specified blend area and are visible in the Viewport in
-Edit Mode, Game Mode.
-"""
-
-import os
-import pytest
-
-pytest.importorskip("ly_test_tools")
-
-import ly_remote_console.remote_console_commands as remote_console_commands
-import ly_test_tools.environment.waiter as waiter
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-remote_console_port = 4600
-listener_timeout = 120
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-class TestLayerBlender(object):
-
- @pytest.fixture
- def remote_console_instance(self, request):
- console = remote_console_commands.RemoteConsole()
-
- def teardown():
- if console.connected:
- console.stop()
-
- request.addfinalizer(teardown)
-
- return console
-
- @pytest.mark.test_case_id("C2627906")
- @pytest.mark.BAT
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
- def test_LayerBlender_E2E_Editor(self, workspace, request, editor, project, level, launcher_platform):
- # Make sure temp level doesn't already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- expected_lines = [
- "'Purple Spawner' created",
- "'Pink Spawner' created",
- "'Surface Entity' created",
- "Entity has a Vegetation Layer Spawner component",
- "Entity has a Vegetation Asset List component",
- "Entity has a Box Shape component",
- "Purple Spawner Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Pink Spawner Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Purple Spawner Configuration|Embedded Assets|[0]: SUCCESS",
- "Pink Spawner Configuration|Embedded Assets|[0]: SUCCESS",
- "'Blender' created",
- "Entity has a Vegetation Layer Blender component",
- "Entity has a Box Shape component",
- "Blender Configuration|Vegetation Areas: SUCCESS",
- "Blender Box Shape|Box Configuration|Dimensions: SUCCESS",
- "LayerBlender_E2E_Editor: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "LayerBlender_E2E_Editor.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C2627906")
- @pytest.mark.BAT
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.parametrize("launcher_platform", ['windows'])
- def test_LayerBlender_E2E_Launcher(self, workspace, project, launcher, level, remote_console_instance,
- launcher_platform):
-
- launcher.args.extend(["-rhi=Null"])
- launcher.start()
- assert launcher.is_alive(), "Launcher failed to start"
-
- # Wait for test script to quit the launcher. If wait_for returns exc, test was not successful
- waiter.wait_for(lambda: not launcher.is_alive(), timeout=300)
-
- # Verify launcher quit successfully and did not crash
- ret_code = launcher.get_returncode()
- assert ret_code == 0, "Test failed. See Game.log for details"
-
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlocker.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlocker.py
deleted file mode 100755
index d0889f17a4..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerBlocker.py
+++ /dev/null
@@ -1,56 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestLayerBlocker(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C2793772")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- def test_LayerBlocker_InstancesBlockedInConfiguredArea(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Surface Entity' created",
- "instance count validation: True (found=400, expected=400)",
- "'Blocker Area' created",
- "instance count validation: True (found=384, expected=384)",
- "LayerBlocker_InstancesBlocked: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "LayerBlocker_InstancesBlockedInConfiguredArea.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerSpawner.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerSpawner.py
deleted file mode 100755
index 65d994f841..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_LayerSpawner.py
+++ /dev/null
@@ -1,142 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestLayerSpawner(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- def teardown():
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- request.addfinalizer(teardown)
-
- @pytest.mark.test_case_id("C4762381")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_LayerSpawner_InheritBehaviorFlag(self, request, editor, level, workspace, launcher_platform):
-
- expected_lines = [
- "LayerSpawner_InheritBehavior: test started",
- "LayerSpawner_InheritBehavior: Vegetation is not planted when Inherit Behavior flag is checked: True",
- "LayerSpawner_InheritBehavior: Vegetation plant when Inherit Behavior flag is unchecked: True",
- "LayerSpawner_InheritBehavior: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "LayerSpawner_InheritBehaviorFlag.py",
- expected_lines=expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C2802020")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_LayerSpawner_InstancesPlantInAllSupportedShapes(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Surface Entity' created",
- "Entity has a Vegetation Reference Shape component",
- "Entity has a Box Shape component",
- "box Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Entity has a Capsule Shape component",
- "capsule Capsule Shape|Capsule Configuration|Height: SUCCESS",
- "capsule Capsule Shape|Capsule Configuration|Radius: SUCCESS",
- "Entity has a Tube Shape component",
- "Entity has a Spline component",
- "Entity has a Sphere Shape component",
- "sphere Sphere Shape|Sphere Configuration|Radius: SUCCESS",
- "Entity has a Cylinder Shape component",
- "cylinder Cylinder Shape|Cylinder Configuration|Radius: SUCCESS",
- "cylinder Cylinder Shape|Cylinder Configuration|Height: SUCCESS",
- "Entity has a Polygon Prism Shape component",
- "Entity has a Compound Shape component",
- "Compound Configuration|Child Shape Entities|[0]: SUCCESS",
- "Compound Configuration|Child Shape Entities|[1]: SUCCESS",
- "Compound Configuration|Child Shape Entities|[2]: SUCCESS",
- "Compound Configuration|Child Shape Entities|[3]: SUCCESS",
- "Compound Configuration|Child Shape Entities|[4]: SUCCESS",
- "Compound Configuration|Child Shape Entities|[5]: SUCCESS",
- "Instance Spawner Configuration|Shape Entity Id: SUCCESS",
- "TestLayerSpawner_AllShapesPlant: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "LayerSpawner_InstancesPlantInAllSupportedShapes.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4765973")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2303")
- def test_LayerSpawner_FilterStageToggle(self, request, editor, level, workspace, launcher_platform):
-
- expected_lines = [
- "LayerSpawner_FilterStageToggle: test started",
- "LayerSpawner_FilterStageToggle: Preprocess filter stage vegetation instance count is as expected: True",
- "LayerSpawner_FilterStageToggle: Postprocess filter vegetation instance stage count is as expected: True",
- "LayerSpawner_FilterStageToggle: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "LayerSpawner_FilterStageToggle.py",
- expected_lines=expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C30000751")
- @pytest.mark.SUITE_sandbox
- @pytest.mark.dynveg_misc
- @pytest.mark.skip # https://github.com/o3de/o3de/issues/2038
- def test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "LayerSpawner_InstanceCameraRefresh: test started",
- "LayerSpawner_InstanceCameraRefresh: test finished",
- "LayerSpawner_InstanceCameraRefresh: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py",
- expected_lines,
- cfg_args=[level],
- null_renderer=False
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_MeshBlocker.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_MeshBlocker.py
deleted file mode 100755
index 197ab6e585..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_MeshBlocker.py
+++ /dev/null
@@ -1,89 +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 logging
-import os
-import pytest
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-
-import editor_python_test_tools.hydra_test_utils as hydra
-import ly_test_tools.environment.file_system as file_system
-
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-logger = logging.getLogger(__name__)
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestMeshBlocker(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, editor, project, level):
- pass
-
- def teardown():
- # delete temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Setup - add the teardown finalizer
- request.addfinalizer(teardown)
- # Make sure the temp level doesn't already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- """
- C3980834: A simple Vegetation Blocker Mesh can be created
- """
- @pytest.mark.test_case_id("C3980834")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.xfail # LYN-3273
- def test_MeshBlocker_InstancesBlockedByMesh(self, request, editor, level, launcher_platform):
- expected_lines = [
- "'Instance Spawner' created",
- "'Surface Entity' created",
- "'Blocker Entity' created",
- "instance count validation: True (found=160, expected=160)",
- "MeshBlocker_InstancesBlockedByMesh: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "MeshBlocker_InstancesBlockedByMesh.py",
- expected_lines,
- cfg_args=[level]
- )
-
- """
- C4766030: Mesh Height Percent Min/Max values can be set to fine tune the blocked area
- """
- @pytest.mark.test_case_id("C4766030")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_area
- @pytest.mark.xfail # LYN-3273
- def test_MeshBlocker_InstancesBlockedByMeshHeightTuning(self, request, editor, level, launcher_platform):
- expected_lines = [
- "'Instance Spawner' created",
- "'Surface Entity' created",
- "'Blocker Entity' created",
- "Blocker Entity Configuration|Mesh Height Percent Max: SUCCESS",
- "instance count validation: True (found=127, expected=127)",
- "MeshBlocker_InstancesBlockedByMeshHeightTuning: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "MeshBlocker_InstancesBlockedByMeshHeightTuning.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_MeshSurfaceTagEmitter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_MeshSurfaceTagEmitter.py
deleted file mode 100755
index fd3a2f6514..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_MeshSurfaceTagEmitter.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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize('project', ['AutomatedTesting'])
-@pytest.mark.parametrize('level', ['tmp_level'])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestMeshSurfaceTagEmitter(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C2908172")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_surfacetagemitter
- def test_MeshSurfaceTagEmitter_DependentOnMeshComponent(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "Entity has a Mesh Surface Tag Emitter component",
- "New Entity Created",
- "Mesh Surface Tag Emitter is Disabled",
- "Entity has a Mesh component",
- "Mesh Surface Tag Emitter is Enabled",
- "MeshSurfaceTagEmitter_DependentOnMeshComponent: result=SUCCESS"
- ]
-
- unexpected_lines = [
- "Mesh Surface Tag Emitter is Enabled. But It should be disabled before adding Mesh",
- "Mesh Surface Tag Emitter is Disabled. But It should be enabled after adding Mesh",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "MeshSurfaceTagEmitter_DependentOnMeshComponent.py",
- expected_lines,
- unexpected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C2908174")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_surfacetagemitter
- def test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "Added SurfaceTag: container count is 1",
- "Removed SurfaceTag: container count is 0",
- "MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSucessfully: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_PhysXColliderSurfaceTagEmitter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_PhysXColliderSurfaceTagEmitter.py
deleted file mode 100755
index 03b7a968f8..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_PhysXColliderSurfaceTagEmitter.py
+++ /dev/null
@@ -1,53 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize('project', ['AutomatedTesting'])
-@pytest.mark.parametrize('level', ['tmp_level'])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestPhysXColliderSurfaceTagEmitter(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C29053640")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_surfacetagemitter
- def test_PhysXColliderSurfaceTagEmitter_E2E_Editor(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "PhysXColliderSurfaceTagEmitter_E2E_Editor: test started",
- "PhysXColliderSurfaceTagEmitter_E2E_Editor: test finished",
- "PhysXColliderSurfaceTagEmitter_E2E_Editor: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "PhysXColliderSurfaceTagEmitter_E2E_Editor.py",
- expected_lines=expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_PositionModifier.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_PositionModifier.py
deleted file mode 100755
index ebbd58557e..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_PositionModifier.py
+++ /dev/null
@@ -1,79 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestPositionModifier(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4874099", "C4814461")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- def test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "Vegetation Position Modifier component was added to entity",
- "'Planting Surface' created",
- "Entity has a Constant Gradient component",
- "PositionModifierComponentAndOverrides_InstanceOffset: result=SUCCESS",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4874100")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2303")
- def test_PositionModifier_AutoSnapToSurfaceWorks(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Planting Surface' created",
- "Instance Spawner Configuration|Position X|Range Min: SUCCESS",
- "Instance Spawner Configuration|Position X|Range Max: SUCCESS",
- "PositionModifier_AutoSnapToSurface: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "PositionModifier_AutoSnapToSurfaceWorks.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_RotationModifier.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_RotationModifier.py
deleted file mode 100755
index 1dea332f7d..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_RotationModifier.py
+++ /dev/null
@@ -1,97 +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 logging
-import os
-import pytest
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-
-import editor_python_test_tools.hydra_test_utils as hydra
-import ly_test_tools.environment.file_system as file_system
-
-logger = logging.getLogger(__name__)
-
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestRotationModifier(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- # delete temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Setup - add the teardown finalizer
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4896922")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- def test_RotationModifier_InstancesRotateWithinRange(self, request, editor, level, launcher_platform) -> None:
- """
- Launches editor and run test script to test that rotation modifier works for all axis.
- Manual test case: C4896922
- """
-
- expected_lines = [
- "'Spawner Entity' created",
- "'Surface Entity' created",
- "'Gradient Entity' created",
- "Entity has a Vegetation Asset List component",
- "Entity has a Vegetation Layer Spawner component",
- "Entity has a Vegetation Rotation Modifier component",
- "Entity has a Box Shape component",
- "Entity has a Constant Gradient component",
- "RotationModifier_InstancesRotateWithinRange: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "RotationModifier_InstancesRotateWithinRange.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4814460")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- def test_RotationModifierOverrides_InstancesRotateWithinRange(self, request, editor, level, launcher_platform) -> None:
-
- expected_lines = [
- "'Spawner Entity' created",
- "'Surface Entity' created",
- "'Gradient Entity' created",
- "Entity has a Vegetation Layer Spawner component",
- "Entity has a Vegetation Asset List component",
- "Spawner Entity Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Entity has a Vegetation Rotation Modifier component",
- "Spawner Entity Configuration|Embedded Assets|[0]|Rotation Modifier|Override Enabled: SUCCESS",
- "Spawner Entity Configuration|Allow Per-Item Overrides: SUCCESS",
- "Entity has a Constant Gradient component",
- "Entity has a Box Shape component",
- "Spawner Entity Configuration|Rotation Z|Gradient|Gradient Entity Id: SUCCESS",
- "RotationModifierOverrides_InstancesRotateWithinRange: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "RotationModifierOverrides_InstancesRotateWithinRange.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_ScaleModifier.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_ScaleModifier.py
deleted file mode 100755
index 62f6c0bbad..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_ScaleModifier.py
+++ /dev/null
@@ -1,91 +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
-"""
-
-"""
-C4814462: Vegetation instances have random scale between 0.1 and 1.0 applied.
-"""
-
-import os
-import pytest
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-
-import editor_python_test_tools.hydra_test_utils as hydra
-import ly_test_tools.environment.file_system as file_system
-
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestScaleOverrideWorksSuccessfully(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4814462")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- def test_ScaleModifierOverrides_InstancesProperlyScale(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Spawner Entity' created",
- "'Surface Entity' created",
- "Entity has a Vegetation Scale Modifier component",
- "'Gradient Entity' created",
- "Scale Min and Scale Max are set to 0.1 and 1.0 in Vegetation Asset List",
- "Entity has a Random Noise Gradient component",
- "Entity has a Gradient Transform Modifier component",
- "Entity has a Box Shape component",
- "Spawner Entity Configuration|Gradient|Gradient Entity Id: SUCCESS",
- "ScaleModifierOverrides_InstancesProperlyScale: result=SUCCESS"
- ]
-
- unexpected_lines = ["Scale Min and Scale Max are not set to 0.1 and 1.0 in Vegetation Asset List"]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "ScaleModifierOverrides_InstancesProperlyScale.py",
- expected_lines,
- unexpected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4896937")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- def test_ScaleModifier_InstancesProperlyScale(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Spawner Entity' created",
- "Entity has a Vegetation Scale Modifier component",
- "'Surface Entity' created",
- "'Gradient Entity' created",
- "Spawner Entity Configuration|Gradient|Gradient Entity Id: SUCCESS",
- "Spawner Entity Configuration|Range Min: SUCCESS",
- "Spawner Entity Configuration|Range Max: SUCCESS",
- "ScaleModifier_InstancesProperlyScale: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "ScaleModifier_InstancesProperlyScale.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_ShapeIntersectionFilter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_ShapeIntersectionFilter.py
deleted file mode 100755
index d2ed0318ca..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_ShapeIntersectionFilter.py
+++ /dev/null
@@ -1,56 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip('ly_test_tools')
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), 'EditorScripts')
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestShapeIntersectionFilter(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4874094")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Planting Surface' created",
- "instance count validation: True (found=49, expected=49)",
- "instance count validation: True (found=121, expected=121)",
- "instance count validation: True (found=400, expected=400)",
- "ShapeIntersectionFilter_InstancePlanting: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "ShapeIntersectionFilter_InstancesPlantInAssignedShape.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SlopeAlignmentModifier.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SlopeAlignmentModifier.py
deleted file mode 100755
index 3a01521d8e..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SlopeAlignmentModifier.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
-"""
-
-"""
-C4896941 - Surface Alignment functions as expected
-C4814459 - Surface Alignment overrides function as expected
-"""
-
-import os
-import pytest
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import editor_python_test_tools.hydra_test_utils as hydra
-import ly_test_tools.environment.file_system as file_system
-
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestSlopeAlignmentModifier(object):
-
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C4896941")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2303")
- def test_SlopeAlignmentModifier_InstanceSurfaceAlignment(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "Vegetation Slope Alignment Modifier component was added to entity",
- "Instance Spawner Configuration|Alignment Coefficient Min: SUCCESS",
- "Constant Gradient component was added to entity",
- "Instance Spawner Configuration|Gradient|Gradient Entity Id: SUCCESS",
- "SlopeAlignmentModifier: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SlopeAlignmentModifier_InstanceSurfaceAlignment.py",
- expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C4814459")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_modifier
- @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2303")
- def test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "Instance Spawner Configuration|Allow Per-Item Overrides: SUCCESS",
- "Instance Spawner Configuration|Embedded Assets|[0]|Surface Slope Alignment|Override Enabled: SUCCESS",
- "Instance Spawner Configuration|Embedded Assets|[0]|Surface Slope Alignment|Max: SUCCESS",
- "Instance Spawner Configuration|Embedded Assets|[0]|Surface Slope Alignment|Min: SUCCESS",
- "SlopeAlignmentModifierOverrides: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SlopeFilter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SlopeFilter.py
deleted file mode 100755
index 3065b2df61..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SlopeFilter.py
+++ /dev/null
@@ -1,96 +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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestSlopeFilter(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- def teardown():
- # Cleanup our temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
- request.addfinalizer(teardown)
-
- @pytest.mark.test_case_id("C4874097")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_SlopeFilter_FilterStageToggle(self, request, editor, level, workspace, launcher_platform):
- cfg_args = [level]
-
- expected_lines = [
- "SlopeFilter_FilterStageToggle: test started",
- "SlopeFilter_FilterStageToggle: Vegetation plant only in the areas where the Box overlaps with the vegetation area's boundaries: True",
- "SlopeFilter_FilterStageToggle: Vegetation plant only in the areas where the Cylinder overlaps with the vegetation area's boundaries: True",
- "SlopeFilter_FilterStageToggle: Vegetation instances count equal to expected value for PREPROCESS filter stage: True",
- "SlopeFilter_FilterStageToggle: Vegetation instances count equal to expected value for POSTPROCESS filter stage: True",
- "SlopeFilter_FilterStageToggle: result=SUCCESS",
- ]
-
- unexpected_lines = [
- "SlopeFilter_FilterStageToggle: Vegetation plant only in the areas where the Box overlaps with the vegetation area's boundaries: False",
- "SlopeFilter_FilterStageToggle: Vegetation plant only in the areas where the Cylinder overlaps with the vegetation area's boundaries: False",
- "SlopeFilter_FilterStageToggle: Vegetation instances count equal to expected value for PREPROCESS filter stage: False",
- "SlopeFilter_FilterStageToggle: Vegetation instances count equal to expected value for POSTPROCESS filter stage: False",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SlopeFilter_FilterStageToggle.py",
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- cfg_args=cfg_args
- )
-
- @pytest.mark.test_case_id("C4814464", "C4874096")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2303")
- def test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Planting Surface' created",
- "'Sloped Planting Surface' created",
- "instance count validation: True (found=1720, expected=1720)",
- "Instance Spawner Configuration|Slope Min: SUCCESS",
- "Instance Spawner Configuration|Slope Max: SUCCESS",
- "instance count validation: True (found=48, expected=48)",
- "Instance Spawner Configuration|Embedded Assets|[0]|Slope Filter|Min: SUCCESS",
- "Instance Spawner Configuration|Embedded Assets|[0]|Slope Filter|Max: SUCCESS",
- "instance count validation: True (found=12, expected=12)",
- "SlopeFilter_InstancesPlantOnValidSlope: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SurfaceMaskFilter.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SurfaceMaskFilter.py
deleted file mode 100755
index 7101a8e286..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SurfaceMaskFilter.py
+++ /dev/null
@@ -1,150 +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 pytest
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-
-import editor_python_test_tools.hydra_test_utils as hydra
-import ly_test_tools.environment.file_system as file_system
-
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestSurfaceMaskFilter(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- # delete temp level
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Setup - add the teardown finalizer
- request.addfinalizer(teardown)
-
- # Make sure the temp level doesn't already exist
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- # Simple validation test to ensure that SurfaceTag can be created, set to a value, and compared to another SurfaceTag.
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_SurfaceMaskFilter_BasicSurfaceTagCreation(self, request, level, editor, launcher_platform):
-
- expected_lines = [
- "SurfaceTag test started",
- "SurfaceTag equal tag comparison is True expected True",
- "SurfaceTag not equal tag comparison is False expected False",
- "SurfaceTag test finished",
- "TestSurfaceMaskFilter_BasicSurfaceTagCreation: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- 'SurfaceMaskFilter_BasicSurfaceTagCreation.py',
- expected_lines=expected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C2561342")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "Instance Spawner Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Instance Spawner Configuration|Embedded Assets|[0]: SUCCESS",
- "'Surface Entity 1' created",
- "Surface Entity 1 Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Surface Entity 1 Configuration|Generated Tags: SUCCESS",
- "'Surface Entity 2' created",
- "Surface Entity 2 Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Surface Entity 2 Configuration|Generated Tags: SUCCESS",
- "SurfaceMaskFilter_ExclusionList: Expected 39 instances - Found 39 instances",
- "Instance Spawner Configuration|Exclusion|Weight Max: SUCCESS",
- "SurfaceMaskFilter_ExclusionList: Expected 169 instances - Found 169 instances",
- "SurfaceMaskFilter_ExclusionList: result=SUCCESS"
- ]
-
- unexpected_lines = ["Failed to add an Exclusive surface mask filter of terrainHole"]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SurfaceMaskFilter_ExclusionList.py",
- expected_lines,
- unexpected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C2561341")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "Instance Spawner Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Instance Spawner Configuration|Embedded Assets|[0]: SUCCESS",
- "'Surface Entity 1' created",
- "Surface Entity 1 Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Surface Entity 1 Configuration|Generated Tags: SUCCESS",
- "'Surface Entity 2' created",
- "Surface Entity 2 Box Shape|Box Configuration|Dimensions: SUCCESS",
- "Surface Entity 2 Configuration|Generated Tags: SUCCESS",
- "SurfaceMaskFilter_InclusionList: Expected 130 instances - Found 130 instances",
- "Instance Spawner Configuration|Inclusion|Weight Max: SUCCESS",
- "SurfaceMaskFilter_InclusionList: Expected 0 instances - Found 0 instances",
- "SurfaceMaskFilter_InclusionList: result=SUCCESS"
- ]
-
- unexpected_lines = ["Failed to add an Inclusive surface mask filter of terrainHole"]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SurfaceMaskFilter_InclusionList.py",
- expected_lines,
- unexpected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C3711666")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_filter
- def test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(self, request, editor, level,
- launcher_platform):
-
- expected_lines = [
- "'Instance Spawner' created",
- "'Surface Entity A' created",
- "'Surface Entity B' created",
- "'Surface Entity C' created",
- "instance count validation: True (found=725, expected=725)",
- "instance count validation: True (found=400, expected=400)",
- "instance count validation: True (found=225, expected=225)",
- "instance count validation: True (found=100, expected=100)",
- "SurfaceMaskFilter_MultipleDescriptorOverrides: result=SUCCESS"
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py",
- expected_lines,
- cfg_args=[level]
- )
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SystemSettings.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SystemSettings.py
deleted file mode 100755
index 0b00a1fa83..0000000000
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/test_SystemSettings.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 pytest
-import logging
-
-# Bail on the test if ly_test_tools doesn't exist.
-pytest.importorskip("ly_test_tools")
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-
-logger = logging.getLogger(__name__)
-test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
-
-
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("level", ["tmp_level"])
-@pytest.mark.usefixtures("automatic_process_killer")
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestSystemSettings(object):
- @pytest.fixture(autouse=True)
- def setup_teardown(self, request, workspace, project, level):
- def teardown():
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- request.addfinalizer(teardown)
-
- file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
-
- @pytest.mark.test_case_id("C2646869")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_SystemSettings_SectorPointDensity(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "SystemSettings_SectorPointDensity: test started",
- "SystemSettings_SectorPointDensity: Vegetation instances count equal to expected value before changing sector point density: True",
- "SystemSettings_SectorPointDensity: Vegetation instances count equal to expected value after changing sector point density: True",
- "SystemSettings_SectorPointDensity: result=SUCCESS",
- ]
-
- unexpected_lines = [
- "SystemSettings_SectorPointDensity: Vegetation instances count equal to expected value before changing sector point density: False",
- "SystemSettings_SectorPointDensity: Vegetation instances count equal to expected value after changing sector point density: False",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SystemSettings_SectorPointDensity.py",
- expected_lines,
- unexpected_lines=unexpected_lines,
- cfg_args=[level]
- )
-
- @pytest.mark.test_case_id("C2646870")
- @pytest.mark.SUITE_periodic
- @pytest.mark.dynveg_misc
- def test_SystemSettings_SectorSize(self, request, editor, level, launcher_platform):
-
- expected_lines = [
- "SystemSettings_SectorSize: test started",
- "SystemSettings_SectorSize: Vegetation instances count equal to expected value before changing sector size: True",
- "SystemSettings_SectorSize: Vegetation instances count equal to expected value after changing sector size: True",
- "SystemSettings_SectorSize: result=SUCCESS",
- ]
-
- unexpected_lines = [
- "SystemSettings_SectorSize: Vegetation instances count equal to expected value before changing sector size: False",
- "SystemSettings_SectorSize: Vegetation instances count equal to expected value after changing sector size: False",
- ]
-
- hydra.launch_and_validate_results(
- request,
- test_directory,
- editor,
- "SystemSettings_SectorSize.py",
- expected_lines,
- unexpected_lines=unexpected_lines,
- cfg_args=[level]
- )
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43b0dd240e..e659270f84 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,11 +29,11 @@ include(cmake/PAL.cmake)
include(cmake/PALTools.cmake)
include(cmake/RuntimeDependencies.cmake)
include(cmake/Configurations.cmake) # Requires to be after PAL so we get platform variable definitions
-include(cmake/Install.cmake)
include(cmake/Dependencies.cmake)
include(cmake/Deployment.cmake)
include(cmake/3rdParty.cmake)
include(cmake/LYPython.cmake)
+include(cmake/Install.cmake)
include(cmake/LYWrappers.cmake)
include(cmake/Gems.cmake)
include(cmake/UnitTest.cmake)
diff --git a/Code/Editor/2DViewport.h b/Code/Editor/2DViewport.h
index 4ffda18514..007c1a47d3 100644
--- a/Code/Editor/2DViewport.h
+++ b/Code/Editor/2DViewport.h
@@ -35,32 +35,32 @@ public:
Q2DViewport(QWidget* parent = nullptr);
virtual ~Q2DViewport();
- virtual void SetType(EViewportType type);
- virtual EViewportType GetType() const { return m_viewType; }
- virtual float GetAspectRatio() const { return 1.0f; };
+ void SetType(EViewportType type) override;
+ EViewportType GetType() const override { return m_viewType; }
+ float GetAspectRatio() const override { return 1.0f; };
- virtual void ResetContent();
- virtual void UpdateContent(int flags);
+ void ResetContent() override;
+ void UpdateContent(int flags) override;
public slots:
// Called every frame to update viewport.
- virtual void Update();
+ void Update() override;
public:
//! Map world space position to viewport position.
- virtual QPoint WorldToView(const Vec3& wp) const;
+ QPoint WorldToView(const Vec3& wp) const override;
- virtual QPoint WorldToViewParticleEditor(const Vec3& wp, int width, int height) const; //Eric@conffx
+ QPoint WorldToViewParticleEditor(const Vec3& wp, int width, int height) const override; //Eric@conffx
//! Map viewport position to world space position.
- virtual Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override;
+ Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override;
//! Map viewport position to world space ray from camera.
- virtual void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const;
+ void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const override;
void OnTitleMenu(QMenu* menu) override;
- virtual bool HitTest(const QPoint& point, HitContext& hitInfo) override;
- virtual bool IsBoundsVisible(const AABB& box) const;
+ bool HitTest(const QPoint& point, HitContext& hitInfo) override;
+ bool IsBoundsVisible(const AABB& box) const override;
// ovverided from CViewport.
float GetScreenScaleFactor(const Vec3& worldPoint) const override;
@@ -111,8 +111,8 @@ protected:
virtual void SetZoom(float fZoomFactor, const QPoint& center);
// overrides from CViewport.
- virtual void MakeConstructionPlane(int axis);
- virtual const Matrix34& GetConstructionMatrix(RefCoordSys coordSys);
+ void MakeConstructionPlane(int axis) override;
+ const Matrix34& GetConstructionMatrix(RefCoordSys coordSys) override;
//! Calculate view transformation matrix.
virtual void CalculateViewTM();
@@ -146,9 +146,9 @@ protected:
void showEvent(QShowEvent* event) override;
void paintEvent(QPaintEvent* event) override;
int OnCreate();
- void OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
- void OnRButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
- void OnMouseWheel(Qt::KeyboardModifiers modifiers, short zDelta, const QPoint& pt);
+ void OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point) override;
+ void OnRButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point) override;
+ void OnMouseWheel(Qt::KeyboardModifiers modifiers, short zDelta, const QPoint& pt) override;
void OnDestroy();
protected:
diff --git a/Code/Editor/ActionManager.h b/Code/Editor/ActionManager.h
index 2481b7e3ef..8879bdc1fb 100644
--- a/Code/Editor/ActionManager.h
+++ b/Code/Editor/ActionManager.h
@@ -353,7 +353,7 @@ public:
m_actionHandlers[id] = std::bind(method, object, id);
}
- bool eventFilter(QObject* watched, QEvent* event);
+ bool eventFilter(QObject* watched, QEvent* event) override;
// returns false if the action was already inserted, indicating that the action should not be processed again
bool InsertActionExecuting(int id);
diff --git a/Code/Editor/AnimationContext.h b/Code/Editor/AnimationContext.h
index 98c951eda7..62ffa26634 100644
--- a/Code/Editor/AnimationContext.h
+++ b/Code/Editor/AnimationContext.h
@@ -197,7 +197,7 @@ private:
virtual void OnSequenceRemoved(CTrackViewSequence* pSequence) override;
- virtual void OnEditorNotifyEvent(EEditorNotifyEvent event);
+ virtual void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
void AnimateActiveSequence();
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp
index 18946c7874..9fe4cfd0d2 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp
@@ -141,6 +141,10 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent)
m_ui->m_assetBrowserTreeViewWidget, &AzAssetBrowser::AssetBrowserTreeView::ClearTypeFilter, m_ui->m_searchWidget,
&AzAssetBrowser::SearchWidget::ClearTypeFilter);
+ connect(
+ this, &AzAssetBrowserWindow::SizeChangedSignal, m_ui->m_assetBrowserTableViewWidget,
+ &AzAssetBrowser::AssetBrowserTableView::UpdateSizeSlot);
+
m_ui->m_assetBrowserTreeViewWidget->SetName("AssetBrowserTreeView_main");
}
@@ -164,6 +168,25 @@ QObject* AzAssetBrowserWindow::createListenerForShowAssetEditorEvent(QObject* pa
return listener;
}
+void AzAssetBrowserWindow::resizeEvent(QResizeEvent* resizeEvent)
+{
+ // leftLayout is the parent of the tableView
+ // rightLayout is the parent of the preview window.
+ // Workaround: When docking windows this event keeps holding the old size of the widgets instead of the new one
+ // but the resizeEvent holds the new size of the whole widget
+ // So we have to save the proportions somehow
+ const QWidget* leftLayout = m_ui->m_leftLayout;
+ const QVBoxLayout* rightLayout = m_ui->m_rightLayout;
+
+ const float oldLeftLayoutWidth = aznumeric_cast(leftLayout->geometry().width());
+ const float oldWidth = aznumeric_cast(leftLayout->geometry().width() + rightLayout->geometry().width());
+
+ const float newWidth = oldLeftLayoutWidth * aznumeric_cast(resizeEvent->size().width()) / oldWidth;
+
+ emit SizeChangedSignal(aznumeric_cast(newWidth));
+ QWidget::resizeEvent(resizeEvent);
+}
+
void AzAssetBrowserWindow::OnInitViewToggleButton()
{
CreateSwitchViewMenu();
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h
index bf742b0cf2..753f000300 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h
@@ -53,9 +53,17 @@ public:
static QObject* createListenerForShowAssetEditorEvent(QObject* parent);
+
+Q_SIGNALS:
+ void SizeChangedSignal(int newWidth);
+
+protected:
+ void resizeEvent(QResizeEvent* resizeEvent) override;
+
private:
void OnInitViewToggleButton();
void UpdateDisplayInfo();
+
protected slots:
void CreateSwitchViewMenu();
void SetExpandedAssetBrowserMode();
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui
index df7474d9d4..a345438aed 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.ui
@@ -140,9 +140,6 @@
QAbstractItemView::ScrollPerPixel
-
- false
-
true
@@ -201,6 +198,11 @@
AzToolsFramework/AssetBrowser/Search/SearchWidget.h
1
+
+ AzQtComponents::TableView
+ QTreeView
+ AzQtComponents/Components/Widgets/TableView.h
+
AzToolsFramework::AssetBrowser::AssetBrowserTreeView
QTreeView
@@ -214,7 +216,7 @@
AzToolsFramework::AssetBrowser::AssetBrowserTableView
- QTableView
+ AzQtComponents::TableView
AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
diff --git a/Code/Editor/BaseLibrary.h b/Code/Editor/BaseLibrary.h
index 6c807df56b..55079d3fde 100644
--- a/Code/Editor/BaseLibrary.h
+++ b/Code/Editor/BaseLibrary.h
@@ -40,57 +40,57 @@ public:
//! Set library name.
virtual void SetName(const QString& name);
//! Get library name.
- const QString& GetName() const;
+ const QString& GetName() const override;
//! Set new filename for this library.
virtual bool SetFilename(const QString& filename, [[maybe_unused]] bool checkForUnique = true) { m_filename = filename.toLower(); return true; };
- const QString& GetFilename() const { return m_filename; };
+ const QString& GetFilename() const override { return m_filename; };
- virtual bool Save() = 0;
- virtual bool Load(const QString& filename) = 0;
- virtual void Serialize(XmlNodeRef& node, bool bLoading) = 0;
+ bool Save() override = 0;
+ bool Load(const QString& filename) override = 0;
+ void Serialize(XmlNodeRef& node, bool bLoading) override = 0;
//! Mark library as modified.
- void SetModified(bool bModified = true);
+ void SetModified(bool bModified = true) override;
//! Check if library was modified.
- bool IsModified() const { return m_bModified; };
+ bool IsModified() const override { return m_bModified; };
//////////////////////////////////////////////////////////////////////////
// Working with items.
//////////////////////////////////////////////////////////////////////////
//! Add a new prototype to library.
- void AddItem(IDataBaseItem* item, bool bRegister = true);
+ void AddItem(IDataBaseItem* item, bool bRegister = true) override;
//! Get number of known prototypes.
- int GetItemCount() const { return static_cast(m_items.size()); }
+ int GetItemCount() const override { return static_cast(m_items.size()); }
//! Get prototype by index.
- IDataBaseItem* GetItem(int index);
+ IDataBaseItem* GetItem(int index) override;
//! Delete item by pointer of item.
- void RemoveItem(IDataBaseItem* item);
+ void RemoveItem(IDataBaseItem* item) override;
//! Delete all items from library.
- void RemoveAllItems();
+ void RemoveAllItems() override;
//! Find library item by name.
//! Using linear search.
- IDataBaseItem* FindItem(const QString& name);
+ IDataBaseItem* FindItem(const QString& name) override;
//! Check if this library is local level library.
- bool IsLevelLibrary() const { return m_bLevelLib; };
+ bool IsLevelLibrary() const override { return m_bLevelLib; };
//! Set library to be level library.
- void SetLevelLibrary(bool bEnable) { m_bLevelLib = bEnable; };
+ void SetLevelLibrary(bool bEnable) override { m_bLevelLib = bEnable; };
//////////////////////////////////////////////////////////////////////////
//! Return manager for this library.
- IBaseLibraryManager* GetManager();
+ IBaseLibraryManager* GetManager() override;
// Saves the library with the main tag defined by the parameter name
bool SaveLibrary(const char* name, bool saveEmptyLibrary = false);
//CONFETTI BEGIN
// Used to change the library item order
- virtual void ChangeItemOrder(CBaseLibraryItem* item, unsigned int newLocation) override;
+ void ChangeItemOrder(CBaseLibraryItem* item, unsigned int newLocation) override;
//CONFETTI END
signals:
diff --git a/Code/Editor/BaseLibraryManager.h b/Code/Editor/BaseLibraryManager.h
index 6f0b905760..118c7ef1f0 100644
--- a/Code/Editor/BaseLibraryManager.h
+++ b/Code/Editor/BaseLibraryManager.h
@@ -35,112 +35,112 @@ public:
~CBaseLibraryManager();
//! Clear all libraries.
- virtual void ClearAll() override;
+ void ClearAll() override;
//////////////////////////////////////////////////////////////////////////
// IDocListener implementation.
//////////////////////////////////////////////////////////////////////////
- virtual void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
+ void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
//////////////////////////////////////////////////////////////////////////
// Library items.
//////////////////////////////////////////////////////////////////////////
//! Make a new item in specified library.
- virtual IDataBaseItem* CreateItem(IDataBaseLibrary* pLibrary) override;
+ IDataBaseItem* CreateItem(IDataBaseLibrary* pLibrary) override;
//! Delete item from library and manager.
- virtual void DeleteItem(IDataBaseItem* pItem) override;
+ void DeleteItem(IDataBaseItem* pItem) override;
//! Find Item by its GUID.
- virtual IDataBaseItem* FindItem(REFGUID guid) const;
- virtual IDataBaseItem* FindItemByName(const QString& fullItemName);
- virtual IDataBaseItem* LoadItemByName(const QString& fullItemName);
+ IDataBaseItem* FindItem(REFGUID guid) const override;
+ IDataBaseItem* FindItemByName(const QString& fullItemName) override;
+ IDataBaseItem* LoadItemByName(const QString& fullItemName) override;
virtual IDataBaseItem* FindItemByName(const char* fullItemName);
virtual IDataBaseItem* LoadItemByName(const char* fullItemName);
- virtual IDataBaseItemEnumerator* GetItemEnumerator() override;
+ IDataBaseItemEnumerator* GetItemEnumerator() override;
//////////////////////////////////////////////////////////////////////////
// Set item currently selected.
- virtual void SetSelectedItem(IDataBaseItem* pItem) override;
+ void SetSelectedItem(IDataBaseItem* pItem) override;
// Get currently selected item.
- virtual IDataBaseItem* GetSelectedItem() const override;
- virtual IDataBaseItem* GetSelectedParentItem() const override;
+ IDataBaseItem* GetSelectedItem() const override;
+ IDataBaseItem* GetSelectedParentItem() const override;
//////////////////////////////////////////////////////////////////////////
// Libraries.
//////////////////////////////////////////////////////////////////////////
//! Add Item library.
- virtual IDataBaseLibrary* AddLibrary(const QString& library, bool bIsLevelLibrary = false, bool bIsLoading = true) override;
- virtual void DeleteLibrary(const QString& library, bool forceDeleteLevel = false) override;
+ IDataBaseLibrary* AddLibrary(const QString& library, bool bIsLevelLibrary = false, bool bIsLoading = true) override;
+ void DeleteLibrary(const QString& library, bool forceDeleteLevel = false) override;
//! Get number of libraries.
- virtual int GetLibraryCount() const override { return static_cast(m_libs.size()); };
+ int GetLibraryCount() const override { return static_cast(m_libs.size()); };
//! Get number of modified libraries.
- virtual int GetModifiedLibraryCount() const override;
+ int GetModifiedLibraryCount() const override;
//! Get Item library by index.
- virtual IDataBaseLibrary* GetLibrary(int index) const override;
+ IDataBaseLibrary* GetLibrary(int index) const override;
//! Get Level Item library.
- virtual IDataBaseLibrary* GetLevelLibrary() const override;
+ IDataBaseLibrary* GetLevelLibrary() const override;
//! Find Items Library by name.
- virtual IDataBaseLibrary* FindLibrary(const QString& library) override;
+ IDataBaseLibrary* FindLibrary(const QString& library) override;
//! Find Items Library's index by name.
int FindLibraryIndex(const QString& library) override;
//! Load Items library.
- virtual IDataBaseLibrary* LoadLibrary(const QString& filename, bool bReload = false) override;
+ IDataBaseLibrary* LoadLibrary(const QString& filename, bool bReload = false) override;
//! Save all modified libraries.
- virtual void SaveAllLibs() override;
+ void SaveAllLibs() override;
//! Serialize property manager.
- virtual void Serialize(XmlNodeRef& node, bool bLoading) override;
+ void Serialize(XmlNodeRef& node, bool bLoading) override;
//! Export items to game.
- virtual void Export([[maybe_unused]] XmlNodeRef& node) override {};
+ void Export([[maybe_unused]] XmlNodeRef& node) override {};
//! Returns unique name base on input name.
- virtual QString MakeUniqueItemName(const QString& name, const QString& libName = "") override;
- virtual QString MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName) override;
+ QString MakeUniqueItemName(const QString& name, const QString& libName = "") override;
+ QString MakeFullItemName(IDataBaseLibrary* pLibrary, const QString& group, const QString& itemName) override;
//! Root node where this library will be saved.
- virtual QString GetRootNodeName() override = 0;
+ QString GetRootNodeName() override = 0;
//! Path to libraries in this manager.
- virtual QString GetLibsPath() override = 0;
+ QString GetLibsPath() override = 0;
//////////////////////////////////////////////////////////////////////////
//! Validate library items for errors.
- virtual void Validate() override;
+ void Validate() override;
//////////////////////////////////////////////////////////////////////////
- virtual void GatherUsedResources(CUsedResources& resources) override;
+ void GatherUsedResources(CUsedResources& resources) override;
- virtual void AddListener(IDataBaseManagerListener* pListener) override;
- virtual void RemoveListener(IDataBaseManagerListener* pListener) override;
+ void AddListener(IDataBaseManagerListener* pListener) override;
+ void RemoveListener(IDataBaseManagerListener* pListener) override;
//////////////////////////////////////////////////////////////////////////
- virtual void RegisterItem(CBaseLibraryItem* pItem, REFGUID newGuid) override;
- virtual void RegisterItem(CBaseLibraryItem* pItem) override;
- virtual void UnregisterItem(CBaseLibraryItem* pItem) override;
+ void RegisterItem(CBaseLibraryItem* pItem, REFGUID newGuid) override;
+ void RegisterItem(CBaseLibraryItem* pItem) override;
+ void UnregisterItem(CBaseLibraryItem* pItem) override;
// Only Used internally.
- virtual void OnRenameItem(CBaseLibraryItem* pItem, const QString& oldName) override;
+ void OnRenameItem(CBaseLibraryItem* pItem, const QString& oldName) override;
// Called by items to indicated that they have been modified.
// Sends item changed event to listeners.
- virtual void OnItemChanged(IDataBaseItem* pItem) override;
- virtual void OnUpdateProperties(IDataBaseItem* pItem, bool bRefresh) override;
+ void OnItemChanged(IDataBaseItem* pItem) override;
+ void OnUpdateProperties(IDataBaseItem* pItem, bool bRefresh) override;
QString MakeFilename(const QString& library);
- virtual bool IsUniqueFilename(const QString& library) override;
+ bool IsUniqueFilename(const QString& library) override;
//CONFETTI BEGIN
// Used to change the library item order
- virtual void ChangeLibraryOrder(IDataBaseLibrary* lib, unsigned int newLocation) override;
+ void ChangeLibraryOrder(IDataBaseLibrary* lib, unsigned int newLocation) override;
- virtual bool SetLibraryName(CBaseLibrary* lib, const QString& name) override;
+ bool SetLibraryName(CBaseLibrary* lib, const QString& name) override;
protected:
void SplitFullItemName(const QString& fullItemName, QString& libraryName, QString& itemName);
@@ -199,8 +199,8 @@ public:
m_pMap = pMap;
m_iterator = m_pMap->begin();
}
- virtual void Release() { delete this; };
- virtual IDataBaseItem* GetFirst()
+ void Release() override { delete this; };
+ IDataBaseItem* GetFirst() override
{
m_iterator = m_pMap->begin();
if (m_iterator == m_pMap->end())
@@ -209,7 +209,7 @@ public:
}
return m_iterator->second;
}
- virtual IDataBaseItem* GetNext()
+ IDataBaseItem* GetNext() override
{
if (m_iterator != m_pMap->end())
{
diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt
index 5158ebc6d5..5884795413 100644
--- a/Code/Editor/CMakeLists.txt
+++ b/Code/Editor/CMakeLists.txt
@@ -254,4 +254,35 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_googletest(
NAME Legacy::EditorLib.Tests
)
+
+ ly_add_target(
+ NAME EditorLib.Camera.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
+ NAMESPACE Legacy
+ FILES_CMAKE
+ Lib/Tests/Camera/editor_lib_camera_test_files.cmake
+ INCLUDE_DIRECTORIES
+ PRIVATE
+ .
+ BUILD_DEPENDENCIES
+ PRIVATE
+ AZ::AzCore
+ AZ::AzTest
+ AZ::AzToolsFramework
+ AZ::AzTestShared
+ Legacy::EditorLib
+ Gem::Camera.Editor
+ Gem::AtomToolsFramework.Static
+ RUNTIME_DEPENDENCIES
+ Legacy::EditorLib
+ )
+
+ ly_add_source_properties(
+ SOURCES Lib/Tests/Camera/test_EditorCamera.cpp
+ PROPERTY COMPILE_DEFINITIONS
+ VALUES CAMERA_EDITOR_MODULE="$"
+ )
+
+ ly_add_googletest(
+ NAME Legacy::EditorLib.Camera.Tests
+ )
endif()
diff --git a/Code/Editor/Controls/ColorGradientCtrl.h b/Code/Editor/Controls/ColorGradientCtrl.h
index a3f95fcd8c..bb1a83b0c1 100644
--- a/Code/Editor/Controls/ColorGradientCtrl.h
+++ b/Code/Editor/Controls/ColorGradientCtrl.h
@@ -81,7 +81,7 @@ protected:
HIT_SPLINE,
};
- void paintEvent(QPaintEvent* e);
+ void paintEvent(QPaintEvent* e) override;
void resizeEvent(QResizeEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
diff --git a/Code/Editor/Controls/FolderTreeCtrl.h b/Code/Editor/Controls/FolderTreeCtrl.h
index 48eff10a92..f74cca6143 100644
--- a/Code/Editor/Controls/FolderTreeCtrl.h
+++ b/Code/Editor/Controls/FolderTreeCtrl.h
@@ -83,7 +83,7 @@ protected Q_SLOTS:
void OnIndexDoubleClicked(const QModelIndex& index);
protected:
- virtual void OnFileMonitorChange(const SFileChangeInfo& rChange);
+ void OnFileMonitorChange(const SFileChangeInfo& rChange) override;
void contextMenuEvent(QContextMenuEvent* e) override;
void InitTree();
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h
index 9c49f1ae1a..4bcd6dcaa3 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h
+++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.h
@@ -123,7 +123,7 @@ public:
void SetVariable(IVariable* pVariable) override;
void SyncReflectedVarToIVar(IVariable* pVariable) override;
void SyncIVarToReflectedVar(IVariable* pVariable) override;
- virtual void OnVariableChange(IVariable* var);
+ void OnVariableChange(IVariable* var) override;
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
protected:
diff --git a/Code/Editor/Controls/SplineCtrlEx.cpp b/Code/Editor/Controls/SplineCtrlEx.cpp
index 9e0a954c79..1dc2ff19e1 100644
--- a/Code/Editor/Controls/SplineCtrlEx.cpp
+++ b/Code/Editor/Controls/SplineCtrlEx.cpp
@@ -70,7 +70,7 @@ protected:
m_splineEntries.resize(m_splineEntries.size() + 1);
SplineEntry& entry = m_splineEntries.back();
ISplineSet* pSplineSet = (pCtrl ? pCtrl->m_pSplineSet : nullptr);
- entry.id = (pSplineSet ? pSplineSet->GetIDFromSpline(pSpline) : nullptr);
+ entry.id = (pSplineSet ? pSplineSet->GetIDFromSpline(pSpline) : AZStd::string{});
entry.pSpline = pSpline;
const int numKeys = pSpline->GetKeyCount();
diff --git a/Code/Editor/Controls/SplineCtrlEx.h b/Code/Editor/Controls/SplineCtrlEx.h
index 711cbcf8d4..9bf412f056 100644
--- a/Code/Editor/Controls/SplineCtrlEx.h
+++ b/Code/Editor/Controls/SplineCtrlEx.h
@@ -159,15 +159,15 @@ public:
//////////////////////////////////////////////////////////////////////////
// IKeyTimeSet Implementation
- virtual int GetKeyTimeCount() const;
- virtual float GetKeyTime(int index) const;
- virtual void MoveKeyTimes(int numChanges, int* indices, float scale, float offset, bool copyKeys);
- virtual bool GetKeyTimeSelected(int index) const;
- virtual void SetKeyTimeSelected(int index, bool selected);
- virtual int GetKeyCount(int index) const;
- virtual int GetKeyCountBound() const;
- virtual void BeginEdittingKeyTimes();
- virtual void EndEdittingKeyTimes();
+ int GetKeyTimeCount() const override;
+ float GetKeyTime(int index) const override;
+ void MoveKeyTimes(int numChanges, int* indices, float scale, float offset, bool copyKeys) override;
+ bool GetKeyTimeSelected(int index) const override;
+ void SetKeyTimeSelected(int index, bool selected) override;
+ int GetKeyCount(int index) const override;
+ int GetKeyCountBound() const override;
+ void BeginEdittingKeyTimes() override;
+ void EndEdittingKeyTimes() override;
void SetEditLock(bool bLock) { m_bEditLock = bLock; }
@@ -361,8 +361,8 @@ public:
SplineWidget(QWidget* parent);
virtual ~SplineWidget();
- void update() { QWidget::update(); }
- void update(const QRect& rect) { QWidget::update(rect); }
+ void update() override { QWidget::update(); }
+ void update(const QRect& rect) override { QWidget::update(rect); }
QPoint mapFromGlobal(const QPoint& point) const override { return QWidget::mapFromGlobal(point); }
diff --git a/Code/Editor/Controls/TimelineCtrl.h b/Code/Editor/Controls/TimelineCtrl.h
index f87bdf3410..7e1fc6fcb2 100644
--- a/Code/Editor/Controls/TimelineCtrl.h
+++ b/Code/Editor/Controls/TimelineCtrl.h
@@ -56,7 +56,7 @@ public:
void setGeometry(const QRect& r) override { QWidget::setGeometry(r); }
void SetTimeRange(const Range& r) { m_timeRange = r; }
- void SetTimeMarker(float fTime);
+ void SetTimeMarker(float fTime) override;
float GetTimeMarker() const { return m_fTimeMarker; }
void SetZoom(float fZoom);
@@ -113,7 +113,7 @@ protected:
void OnLButtonUp(const QPoint& point, Qt::KeyboardModifiers modifiers);
void OnRButtonDown(const QPoint& point, Qt::KeyboardModifiers modifiers);
void OnRButtonUp(const QPoint& point, Qt::KeyboardModifiers modifiers);
- void keyPressEvent(QKeyEvent* event);
+ void keyPressEvent(QKeyEvent* event) override;
// Drawing functions
float ClientToTime(int x);
diff --git a/Code/Editor/Core/QtEditorApplication_linux.cpp b/Code/Editor/Core/QtEditorApplication_linux.cpp
index fa39609308..2fd4ef629e 100644
--- a/Code/Editor/Core/QtEditorApplication_linux.cpp
+++ b/Code/Editor/Core/QtEditorApplication_linux.cpp
@@ -8,11 +8,21 @@
#include "QtEditorApplication.h"
+#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include
+#endif
+
namespace Editor
{
- bool EditorQtApplication::nativeEventFilter(const QByteArray& , void* , long* )
+ bool EditorQtApplication::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long*)
{
- // TODO_KDAB_LINUX
+ if (GetIEditor()->IsInGameMode())
+ {
+#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+ AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast(message));
+#endif
+ return true;
+ }
return false;
}
}
diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h
index 4ab37ac1e5..730af7c034 100644
--- a/Code/Editor/CryEdit.h
+++ b/Code/Editor/CryEdit.h
@@ -462,6 +462,7 @@ class CCryDocManager
CCrySingleDocTemplate* m_pDefTemplate = nullptr;
public:
CCryDocManager();
+ virtual ~CCryDocManager() = default;
CCrySingleDocTemplate* SetDefaultTemplate(CCrySingleDocTemplate* pNew);
// Copied from MFC to get rid of the silly ugly unoverridable doc-type pick dialog
virtual void OnFileNew();
diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp
index a61429fc87..07d946c609 100644
--- a/Code/Editor/CryEditDoc.cpp
+++ b/Code/Editor/CryEditDoc.cpp
@@ -1135,7 +1135,6 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
{
// if we're saving to a new folder, we need to copy the old folder tree.
auto pIPak = GetIEditor()->GetSystem()->GetIPak();
- pIPak->Lock();
const QString oldLevelPattern = QDir(oldLevelFolder).absoluteFilePath("*.*");
const QString oldLevelName = Path::GetFile(GetLevelPathName());
@@ -1199,7 +1198,6 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
QFile(filePath).setPermissions(QFile::ReadOther | QFile::WriteOther);
});
- pIPak->Unlock();
}
// Save level to XML archive.
@@ -1813,8 +1811,8 @@ bool CCryEditDoc::BackupBeforeSave(bool force)
QString subFolder = theTime.toString("yyyy-MM-dd [HH.mm.ss]");
QString levelName = GetIEditor()->GetGameEngine()->GetLevelName();
- QString backupPath = saveBackupPath + "/" + subFolder + "/";
- gEnv->pCryPak->MakeDir(backupPath.toUtf8().data());
+ QString backupPath = saveBackupPath + "/" + subFolder;
+ AZ::IO::FileIOBase::GetDirectInstance()->CreatePath(backupPath.toUtf8().data());
QString sourcePath = QString::fromUtf8(resolvedLevelPath) + "/";
@@ -2028,7 +2026,7 @@ const char* CCryEditDoc::GetTemporaryLevelName() const
void CCryEditDoc::DeleteTemporaryLevel()
{
QString tempLevelPath = (Path::GetEditingGameDataFolder() + "/Levels/" + GetTemporaryLevelName()).c_str();
- GetIEditor()->GetSystem()->GetIPak()->ClosePacks(tempLevelPath.toUtf8().data(), AZ::IO::IArchive::EPathResolutionRules::FLAGS_ADD_TRAILING_SLASH);
+ GetIEditor()->GetSystem()->GetIPak()->ClosePacks(tempLevelPath.toUtf8().data());
CFileUtil::Deltree(tempLevelPath.toUtf8().data(), true);
}
diff --git a/Code/Editor/Dialogs/PythonScriptsDialog.cpp b/Code/Editor/Dialogs/PythonScriptsDialog.cpp
index 7c6b445387..e95fb90c0a 100644
--- a/Code/Editor/Dialogs/PythonScriptsDialog.cpp
+++ b/Code/Editor/Dialogs/PythonScriptsDialog.cpp
@@ -79,6 +79,8 @@ CPythonScriptsDialog::CPythonScriptsDialog(QWidget* parent)
GetGemSourcePathsVisitor(AZ::SettingsRegistryInterface& settingsRegistry)
: m_settingsRegistry(settingsRegistry)
{}
+
+ using AZ::SettingsRegistryInterface::Visitor::Visit;
void Visit(AZStd::string_view path, AZStd::string_view, AZ::SettingsRegistryInterface::Type,
AZStd::string_view value) override
{
diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp
index 498d6f3353..e375e98fb6 100644
--- a/Code/Editor/EditorModularViewportCameraComposer.cpp
+++ b/Code/Editor/EditorModularViewportCameraComposer.cpp
@@ -9,6 +9,7 @@
#include
#include
+#include
#include
#include
#include
@@ -34,10 +35,12 @@ namespace SandboxEditor
: m_viewportId(viewportId)
{
EditorModularViewportCameraComposerNotificationBus::Handler::BusConnect(viewportId);
+ Camera::EditorCameraNotificationBus::Handler::BusConnect();
}
EditorModularViewportCameraComposer::~EditorModularViewportCameraComposer()
{
+ Camera::EditorCameraNotificationBus::Handler::BusDisconnect();
EditorModularViewportCameraComposerNotificationBus::Handler::BusDisconnect();
}
@@ -283,4 +286,22 @@ namespace SandboxEditor
m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId());
m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId());
}
+
+ void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId)
+ {
+ if (viewEntityId.IsValid())
+ {
+ AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
+ AZ::TransformBus::EventResult(worldFromLocal, viewEntityId, &AZ::TransformBus::Events::GetWorldTM);
+
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame,
+ worldFromLocal);
+ }
+ else
+ {
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
+ }
+ }
} // namespace SandboxEditor
diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h
index cb223d39e6..e6e71c976c 100644
--- a/Code/Editor/EditorModularViewportCameraComposer.h
+++ b/Code/Editor/EditorModularViewportCameraComposer.h
@@ -10,13 +10,16 @@
#include
#include
+#include
#include
#include
namespace SandboxEditor
{
//! Type responsible for building the editor's modular viewport camera controller.
- class EditorModularViewportCameraComposer : private EditorModularViewportCameraComposerNotificationBus::Handler
+ class EditorModularViewportCameraComposer
+ : private EditorModularViewportCameraComposerNotificationBus::Handler
+ , private Camera::EditorCameraNotificationBus::Handler
{
public:
SANDBOX_API explicit EditorModularViewportCameraComposer(AzFramework::ViewportId viewportId);
@@ -32,6 +35,9 @@ namespace SandboxEditor
// EditorModularViewportCameraComposerNotificationBus overrides ...
void OnEditorModularViewportCameraComposerSettingsChanged() override;
+ // EditorCameraNotificationBus overrides ...
+ void OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId) override;
+
AZStd::shared_ptr m_firstPersonRotateCamera;
AZStd::shared_ptr m_firstPersonPanCamera;
AZStd::shared_ptr m_firstPersonTranslateCamera;
diff --git a/Code/Editor/EditorPreferencesPageViewportGeneral.cpp b/Code/Editor/EditorPreferencesPageViewportGeneral.cpp
index a9eec22e69..77560e24f8 100644
--- a/Code/Editor/EditorPreferencesPageViewportGeneral.cpp
+++ b/Code/Editor/EditorPreferencesPageViewportGeneral.cpp
@@ -5,9 +5,11 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#include "EditorDefs.h"
#include "EditorPreferencesPageViewportGeneral.h"
+#include "EditorViewportSettings.h"
#include
@@ -15,7 +17,6 @@
#include "DisplaySettings.h"
#include "Settings.h"
-
void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& serialize)
{
serialize.Class()
@@ -23,7 +24,8 @@ void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& seria
->Field("Sync2DViews", &General::m_sync2DViews)
->Field("DefaultFOV", &General::m_defaultFOV)
->Field("DefaultAspectRatio", &General::m_defaultAspectRatio)
- ->Field("EnableContextMenu", &General::m_enableContextMenu);
+ ->Field("EnableContextMenu", &General::m_contextMenuEnabled)
+ ->Field("StickySelect", &General::m_stickySelectEnabled);
serialize.Class()
->Version(1)
@@ -46,10 +48,12 @@ void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& seria
->Field("ShowGridGuide", &Display::m_showGridGuide)
->Field("DisplayDimensions", &Display::m_displayDimension);
+ // clang-format off
serialize.Class()
->Version(1)
->Field("SwapXY", &MapViewport::m_swapXY)
->Field("Resolution", &MapViewport::m_resolution);
+ // clang-format on
serialize.Class()
->Version(1)
@@ -80,31 +84,51 @@ void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& seria
editContext->Class("General Viewport Settings", "")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &General::m_sync2DViews, "Synchronize 2D Viewports", "Synchronize 2D Viewports")
->DataElement(AZ::Edit::UIHandlers::SpinBox, &General::m_defaultFOV, "Perspective View FOV", "Perspective View FOV")
- ->Attribute("Multiplier", RAD2DEG(1))
- ->Attribute(AZ::Edit::Attributes::Min, 1.0f)
- ->Attribute(AZ::Edit::Attributes::Max, 120.0f)
- ->DataElement(AZ::Edit::UIHandlers::SpinBox, &General::m_defaultAspectRatio, "Perspective View Aspect Ratio", "Perspective View Aspect Ratio")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &General::m_enableContextMenu, "Enable Right-Click Context Menu", "Enable Right-Click Context Menu");
+ ->Attribute("Multiplier", RAD2DEG(1))
+ ->Attribute(AZ::Edit::Attributes::Min, 1.0f)
+ ->Attribute(AZ::Edit::Attributes::Max, 120.0f)
+ ->DataElement(
+ AZ::Edit::UIHandlers::SpinBox, &General::m_defaultAspectRatio, "Perspective View Aspect Ratio",
+ "Perspective View Aspect Ratio")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &General::m_contextMenuEnabled, "Enable Right-Click Context Menu",
+ "Enable Right-Click Context Menu")
+ ->DataElement(AZ::Edit::UIHandlers::CheckBox, &General::m_stickySelectEnabled, "Enable Sticky Select", "Enable Sticky Select");
editContext->Class("Viewport Display Settings", "")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showSafeFrame, "Show 4:3 Aspect Ratio Frame", "Show 4:3 Aspect Ratio Frame")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_highlightSelGeom, "Highlight Selected Geometry", "Highlight Selected Geometry")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_highlightSelVegetation, "Highlight Selected Vegetation", "Highlight Selected Vegetation")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_highlightOnMouseOver, "Highlight Geometry On Mouse Over", "Highlight Geometry On Mouse Over")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_hideMouseCursorWhenCaptured, "Hide Cursor When Captured", "Hide Mouse Cursor When Captured")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_showSafeFrame, "Show 4:3 Aspect Ratio Frame", "Show 4:3 Aspect Ratio Frame")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_highlightSelGeom, "Highlight Selected Geometry", "Highlight Selected Geometry")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_highlightSelVegetation, "Highlight Selected Vegetation",
+ "Highlight Selected Vegetation")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_highlightOnMouseOver, "Highlight Geometry On Mouse Over",
+ "Highlight Geometry On Mouse Over")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_hideMouseCursorWhenCaptured, "Hide Cursor When Captured",
+ "Hide Mouse Cursor When Captured")
->DataElement(AZ::Edit::UIHandlers::SpinBox, &Display::m_dragSquareSize, "Drag Square Size", "Drag Square Size")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_displayLinks, "Display Object Links", "Display Object Links")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_displayTracks, "Display Animation Tracks", "Display Animation Tracks")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_alwaysShowRadii, "Always Show Radii", "Always Show Radii")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showBBoxes, "Show Bounding Boxes", "Show Bounding Boxes")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_drawEntityLabels, "Always Draw Entity Labels", "Always Draw Entity Labels")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showTriggerBounds, "Always Show Trigger Bounds", "Always Show Trigger Bounds")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_drawEntityLabels, "Always Draw Entity Labels", "Always Draw Entity Labels")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_showTriggerBounds, "Always Show Trigger Bounds", "Always Show Trigger Bounds")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showIcons, "Show Object Icons", "Show Object Icons")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_distanceScaleIcons, "Scale Object Icons with Distance", "Scale Object Icons with Distance")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showFrozenHelpers, "Show Helpers of Frozen Objects", "Show Helpers of Frozen Objects")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_distanceScaleIcons, "Scale Object Icons with Distance",
+ "Scale Object Icons with Distance")
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_showFrozenHelpers, "Show Helpers of Frozen Objects",
+ "Show Helpers of Frozen Objects")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_fillSelectedShapes, "Fill Selected Shapes", "Fill Selected Shapes")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_showGridGuide, "Show Snapping Grid Guide", "Show Snapping Grid Guide")
- ->DataElement(AZ::Edit::UIHandlers::CheckBox, &Display::m_displayDimension, "Display Dimension Figures", "Display Dimension Figures");
+ ->DataElement(
+ AZ::Edit::UIHandlers::CheckBox, &Display::m_displayDimension, "Display Dimension Figures", "Display Dimension Figures");
editContext->Class("Map Viewport Settings", "")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &MapViewport::m_swapXY, "Swap X/Y Axis", "Swap X/Y Axis")
@@ -113,42 +137,64 @@ void CEditorPreferencesPage_ViewportGeneral::Reflect(AZ::SerializeContext& seria
editContext->Class("Text Label Settings", "")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &TextLabels::m_labelsOn, "Enabled", "Enabled")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &TextLabels::m_labelsDistance, "Distance", "Distance")
- ->Attribute(AZ::Edit::Attributes::Min, 0.f)
- ->Attribute(AZ::Edit::Attributes::Max, 100000.f);
+ ->Attribute(AZ::Edit::Attributes::Min, 0.f)
+ ->Attribute(AZ::Edit::Attributes::Max, 100000.f);
editContext->Class("Selection Preview Color Settings", "")
->DataElement(AZ::Edit::UIHandlers::Color, &SelectionPreviewColor::m_colorGroupBBox, "Group Bounding Box", "Group Bounding Box")
- ->DataElement(AZ::Edit::UIHandlers::Color, &SelectionPreviewColor::m_colorEntityBBox, "Entity Bounding Box", "Entity Bounding Box")
- ->DataElement(AZ::Edit::UIHandlers::SpinBox, &SelectionPreviewColor::m_fBBoxAlpha, "Bounding Box Highlight Alpha", "Bounding Box Highlight Alpha")
- ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
- ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
+ ->DataElement(
+ AZ::Edit::UIHandlers::Color, &SelectionPreviewColor::m_colorEntityBBox, "Entity Bounding Box", "Entity Bounding Box")
+ ->DataElement(
+ AZ::Edit::UIHandlers::SpinBox, &SelectionPreviewColor::m_fBBoxAlpha, "Bounding Box Highlight Alpha",
+ "Bounding Box Highlight Alpha")
+ ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
+ ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
->DataElement(AZ::Edit::UIHandlers::Color, &SelectionPreviewColor::m_geometryHighlightColor, "Geometry Color", "Geometry Color")
- ->DataElement(AZ::Edit::UIHandlers::Color, &SelectionPreviewColor::m_solidBrushGeometryColor, "Solid Brush Geometry Color", "Solid Brush Geometry Color")
- ->DataElement(AZ::Edit::UIHandlers::SpinBox, &SelectionPreviewColor::m_fgeomAlpha, "Geometry Highlight Alpha", "Geometry Highlight Alpha")
- ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
- ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
- ->DataElement(AZ::Edit::UIHandlers::SpinBox, &SelectionPreviewColor::m_childObjectGeomAlpha, "Child Geometry Highlight Alpha", "Child Geometry Highlight Alpha")
- ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
- ->Attribute(AZ::Edit::Attributes::Max, 1.0f);
+ ->DataElement(
+ AZ::Edit::UIHandlers::Color, &SelectionPreviewColor::m_solidBrushGeometryColor, "Solid Brush Geometry Color",
+ "Solid Brush Geometry Color")
+ ->DataElement(
+ AZ::Edit::UIHandlers::SpinBox, &SelectionPreviewColor::m_fgeomAlpha, "Geometry Highlight Alpha", "Geometry Highlight Alpha")
+ ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
+ ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
+ ->DataElement(
+ AZ::Edit::UIHandlers::SpinBox, &SelectionPreviewColor::m_childObjectGeomAlpha, "Child Geometry Highlight Alpha",
+ "Child Geometry Highlight Alpha")
+ ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
+ ->Attribute(AZ::Edit::Attributes::Max, 1.0f);
editContext->Class("General Viewport Preferences", "General Viewport Preferences")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
- ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_general, "General Viewport Settings", "General Viewport Settings")
- ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_display, "Viewport Display Settings", "Viewport Display Settings")
- ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_map, "Map Viewport Settings", "Map Viewport Settings")
- ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_textLabels, "Text Label Settings", "Text Label Settings")
- ->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_selectionPreviewColor, "Selection Preview Color Settings", "Selection Preview Color Settings");
+ ->DataElement(
+ AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_general, "General Viewport Settings",
+ "General Viewport Settings")
+ ->DataElement(
+ AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_display, "Viewport Display Settings",
+ "Viewport Display Settings")
+ ->DataElement(
+ AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_map, "Map Viewport Settings",
+ "Map Viewport Settings")
+ ->DataElement(
+ AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_textLabels, "Text Label Settings",
+ "Text Label Settings")
+ ->DataElement(
+ AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportGeneral::m_selectionPreviewColor,
+ "Selection Preview Color Settings", "Selection Preview Color Settings");
}
}
-
CEditorPreferencesPage_ViewportGeneral::CEditorPreferencesPage_ViewportGeneral()
{
InitializeSettings();
m_icon = QIcon(":/res/Viewport.svg");
}
+const char* CEditorPreferencesPage_ViewportGeneral::GetCategory()
+{
+ return "Viewports";
+}
+
const char* CEditorPreferencesPage_ViewportGeneral::GetTitle()
{
return "Viewport";
@@ -159,14 +205,25 @@ QIcon& CEditorPreferencesPage_ViewportGeneral::GetIcon()
return m_icon;
}
+void CEditorPreferencesPage_ViewportGeneral::OnCancel()
+{
+ // noop
+}
+
+bool CEditorPreferencesPage_ViewportGeneral::OnQueryCancel()
+{
+ return true;
+}
+
void CEditorPreferencesPage_ViewportGeneral::OnApply()
{
CDisplaySettings* ds = GetIEditor()->GetDisplaySettings();
gSettings.viewports.fDefaultAspectRatio = m_general.m_defaultAspectRatio;
gSettings.viewports.fDefaultFov = m_general.m_defaultFOV;
- gSettings.viewports.bEnableContextMenu = m_general.m_enableContextMenu;
+ gSettings.viewports.bEnableContextMenu = m_general.m_contextMenuEnabled;
gSettings.viewports.bSync2DViews = m_general.m_sync2DViews;
+ SandboxEditor::SetStickySelectEnabled(m_general.m_stickySelectEnabled);
gSettings.viewports.bShowSafeFrame = m_display.m_showSafeFrame;
gSettings.viewports.bHighlightSelectedGeometry = m_display.m_highlightSelGeom;
@@ -202,19 +259,19 @@ void CEditorPreferencesPage_ViewportGeneral::OnApply()
gSettings.objectColorSettings.fChildGeomAlpha = m_selectionPreviewColor.m_childObjectGeomAlpha;
gSettings.objectColorSettings.entityHighlight = QColor(
- static_cast(m_selectionPreviewColor.m_colorEntityBBox.GetR() * 255.0f),
- static_cast(m_selectionPreviewColor.m_colorEntityBBox.GetG() * 255.0f),
- static_cast(m_selectionPreviewColor.m_colorEntityBBox.GetB() * 255.0f));
+ static_cast(m_selectionPreviewColor.m_colorEntityBBox.GetR() * 255.0f),
+ static_cast(m_selectionPreviewColor.m_colorEntityBBox.GetG() * 255.0f),
+ static_cast(m_selectionPreviewColor.m_colorEntityBBox.GetB() * 255.0f));
gSettings.objectColorSettings.groupHighlight = QColor(
- static_cast(m_selectionPreviewColor.m_colorGroupBBox.GetR() * 255.0f),
- static_cast(m_selectionPreviewColor.m_colorGroupBBox.GetG() * 255.0f),
- static_cast(m_selectionPreviewColor.m_colorGroupBBox.GetB() * 255.0f));
+ static_cast(m_selectionPreviewColor.m_colorGroupBBox.GetR() * 255.0f),
+ static_cast(m_selectionPreviewColor.m_colorGroupBBox.GetG() * 255.0f),
+ static_cast(m_selectionPreviewColor.m_colorGroupBBox.GetB() * 255.0f));
gSettings.objectColorSettings.fBBoxAlpha = m_selectionPreviewColor.m_fBBoxAlpha;
gSettings.objectColorSettings.fGeomAlpha = m_selectionPreviewColor.m_fgeomAlpha;
gSettings.objectColorSettings.geometryHighlightColor = QColor(
- static_cast(m_selectionPreviewColor.m_geometryHighlightColor.GetR() * 255.0f),
- static_cast(m_selectionPreviewColor.m_geometryHighlightColor.GetG() * 255.0f),
- static_cast(m_selectionPreviewColor.m_geometryHighlightColor.GetB() * 255.0f));
+ static_cast(m_selectionPreviewColor.m_geometryHighlightColor.GetR() * 255.0f),
+ static_cast(m_selectionPreviewColor.m_geometryHighlightColor.GetG() * 255.0f),
+ static_cast(m_selectionPreviewColor.m_geometryHighlightColor.GetB() * 255.0f));
gSettings.objectColorSettings.solidBrushGeometryColor = QColor(
static_cast(m_selectionPreviewColor.m_solidBrushGeometryColor.GetR() * 255.0f),
static_cast(m_selectionPreviewColor.m_solidBrushGeometryColor.GetG() * 255.0f),
@@ -227,8 +284,9 @@ void CEditorPreferencesPage_ViewportGeneral::InitializeSettings()
m_general.m_defaultAspectRatio = gSettings.viewports.fDefaultAspectRatio;
m_general.m_defaultFOV = gSettings.viewports.fDefaultFov;
- m_general.m_enableContextMenu = gSettings.viewports.bEnableContextMenu;
+ m_general.m_contextMenuEnabled = gSettings.viewports.bEnableContextMenu;
m_general.m_sync2DViews = gSettings.viewports.bSync2DViews;
+ m_general.m_stickySelectEnabled = SandboxEditor::StickySelectEnabled();
m_display.m_showSafeFrame = gSettings.viewports.bShowSafeFrame;
m_display.m_highlightSelGeom = gSettings.viewports.bHighlightSelectedGeometry;
@@ -256,10 +314,22 @@ void CEditorPreferencesPage_ViewportGeneral::InitializeSettings()
m_textLabels.m_labelsDistance = ds->GetLabelsDistance();
m_selectionPreviewColor.m_childObjectGeomAlpha = gSettings.objectColorSettings.fChildGeomAlpha;
- m_selectionPreviewColor.m_colorEntityBBox.Set(static_cast(gSettings.objectColorSettings.entityHighlight.redF()), static_cast(gSettings.objectColorSettings.entityHighlight.greenF()), static_cast(gSettings.objectColorSettings.entityHighlight.blueF()), 1.0f);
- m_selectionPreviewColor.m_colorGroupBBox.Set(static_cast(gSettings.objectColorSettings.groupHighlight.redF()), static_cast(gSettings.objectColorSettings.groupHighlight.greenF()), static_cast(gSettings.objectColorSettings.groupHighlight.blueF()), 1.0f);
+ m_selectionPreviewColor.m_colorEntityBBox.Set(
+ static_cast(gSettings.objectColorSettings.entityHighlight.redF()),
+ static_cast(gSettings.objectColorSettings.entityHighlight.greenF()),
+ static_cast(gSettings.objectColorSettings.entityHighlight.blueF()), 1.0f);
+ m_selectionPreviewColor.m_colorGroupBBox.Set(
+ static_cast(gSettings.objectColorSettings.groupHighlight.redF()),
+ static_cast(gSettings.objectColorSettings.groupHighlight.greenF()),
+ static_cast(gSettings.objectColorSettings.groupHighlight.blueF()), 1.0f);
m_selectionPreviewColor.m_fBBoxAlpha = gSettings.objectColorSettings.fBBoxAlpha;
m_selectionPreviewColor.m_fgeomAlpha = gSettings.objectColorSettings.fGeomAlpha;
- m_selectionPreviewColor.m_geometryHighlightColor.Set(static_cast(gSettings.objectColorSettings.geometryHighlightColor.redF()), static_cast(gSettings.objectColorSettings.geometryHighlightColor.greenF()), static_cast(gSettings.objectColorSettings.geometryHighlightColor.blueF()), 1.0f);
- m_selectionPreviewColor.m_solidBrushGeometryColor.Set(static_cast(gSettings.objectColorSettings.solidBrushGeometryColor.redF()), static_cast(gSettings.objectColorSettings.solidBrushGeometryColor.greenF()), static_cast(gSettings.objectColorSettings.solidBrushGeometryColor.blueF()), 1.0f);
+ m_selectionPreviewColor.m_geometryHighlightColor.Set(
+ static_cast(gSettings.objectColorSettings.geometryHighlightColor.redF()),
+ static_cast(gSettings.objectColorSettings.geometryHighlightColor.greenF()),
+ static_cast(gSettings.objectColorSettings.geometryHighlightColor.blueF()), 1.0f);
+ m_selectionPreviewColor.m_solidBrushGeometryColor.Set(
+ static_cast(gSettings.objectColorSettings.solidBrushGeometryColor.redF()),
+ static_cast(gSettings.objectColorSettings.solidBrushGeometryColor.greenF()),
+ static_cast(gSettings.objectColorSettings.solidBrushGeometryColor.blueF()), 1.0f);
}
diff --git a/Code/Editor/EditorPreferencesPageViewportGeneral.h b/Code/Editor/EditorPreferencesPageViewportGeneral.h
index a042bcf19b..be89cc6df4 100644
--- a/Code/Editor/EditorPreferencesPageViewportGeneral.h
+++ b/Code/Editor/EditorPreferencesPageViewportGeneral.h
@@ -5,18 +5,17 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#pragma once
#include "Include/IPreferencesPage.h"
-#include
-#include
-#include
#include
+#include
+#include
+#include
#include
-
-class CEditorPreferencesPage_ViewportGeneral
- : public IPreferencesPage
+class CEditorPreferencesPage_ViewportGeneral : public IPreferencesPage
{
public:
AZ_RTTI(CEditorPreferencesPage_ViewportGeneral, "{8511FF7F-F774-47E1-A99B-3DE3A867E403}", IPreferencesPage)
@@ -26,12 +25,12 @@ public:
CEditorPreferencesPage_ViewportGeneral();
virtual ~CEditorPreferencesPage_ViewportGeneral() = default;
- virtual const char* GetCategory() override { return "Viewports"; }
+ virtual const char* GetCategory() override;
virtual const char* GetTitle() override;
virtual QIcon& GetIcon() override;
virtual void OnApply() override;
- virtual void OnCancel() override {}
- virtual bool OnQueryCancel() override { return true; }
+ virtual void OnCancel() override;
+ virtual bool OnQueryCancel() override;
private:
void InitializeSettings();
@@ -43,7 +42,8 @@ private:
bool m_sync2DViews;
float m_defaultFOV;
float m_defaultAspectRatio;
- bool m_enableContextMenu;
+ bool m_contextMenuEnabled;
+ bool m_stickySelectEnabled;
};
struct Display
@@ -106,5 +106,3 @@ private:
SelectionPreviewColor m_selectionPreviewColor;
QIcon m_icon;
};
-
-
diff --git a/Code/Editor/EditorToolsApplication.cpp b/Code/Editor/EditorToolsApplication.cpp
index 1e5d747e4a..26e608f657 100644
--- a/Code/Editor/EditorToolsApplication.cpp
+++ b/Code/Editor/EditorToolsApplication.cpp
@@ -34,10 +34,14 @@ namespace EditorInternal
: ToolsApplication(argc, argv)
{
EditorToolsApplicationRequests::Bus::Handler::BusConnect();
+ AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
+ AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusConnect();
}
EditorToolsApplication::~EditorToolsApplication()
{
+ AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusDisconnect();
+ AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
EditorToolsApplicationRequests::Bus::Handler::BusDisconnect();
Stop();
}
@@ -48,7 +52,6 @@ namespace EditorInternal
return m_StartupAborted;
}
-
void EditorToolsApplication::RegisterCoreComponents()
{
AzToolsFramework::ToolsApplication::RegisterCoreComponents();
@@ -274,5 +277,14 @@ namespace EditorInternal
Exit();
}
-}
+ AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorToolsApplication::QueryKeyboardModifiers()
+ {
+ return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers());
+ }
+ AZStd::chrono::milliseconds EditorToolsApplication::EditorViewportInputTimeNow()
+ {
+ const auto now = AZStd::chrono::high_resolution_clock::now();
+ return AZStd::chrono::time_point_cast(now).time_since_epoch();
+ }
+} // namespace EditorInternal
diff --git a/Code/Editor/EditorToolsApplication.h b/Code/Editor/EditorToolsApplication.h
index 93916cfc8c..d4e6223445 100644
--- a/Code/Editor/EditorToolsApplication.h
+++ b/Code/Editor/EditorToolsApplication.h
@@ -7,7 +7,9 @@
*/
#pragma once
+
#include
+#include
#include "Core/EditorMetricsPlainTextNameRegistration.h"
#include "EditorToolsApplicationAPI.h"
@@ -19,6 +21,8 @@ namespace EditorInternal
class EditorToolsApplication
: public AzToolsFramework::ToolsApplication
, public EditorToolsApplicationRequests::Bus::Handler
+ , public AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
+ , public AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler
{
public:
EditorToolsApplication(int* argc, char*** argv);
@@ -28,7 +32,7 @@ namespace EditorInternal
void RegisterCoreComponents() override;
- AZ::ComponentTypeList GetRequiredSystemComponents() const;
+ AZ::ComponentTypeList GetRequiredSystemComponents() const override;
void StartCommon(AZ::Entity* systemEntity) override;
@@ -44,6 +48,12 @@ namespace EditorInternal
void CreateReflectionManager() override;
void Reflect(AZ::ReflectContext* context) override;
+ // EditorModifierKeyRequestBus overrides ...
+ AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override;
+
+ // EditorViewportInputTimeNowRequestBus overrides ...
+ AZStd::chrono::milliseconds EditorViewportInputTimeNow() override;
+
protected:
// From EditorToolsApplicationRequests
bool OpenLevel(AZStd::string_view levelName) override;
diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp
index c1bd85a174..063ec125ba 100644
--- a/Code/Editor/EditorViewportSettings.cpp
+++ b/Code/Editor/EditorViewportSettings.cpp
@@ -20,6 +20,7 @@ namespace SandboxEditor
constexpr AZStd::string_view AngleSnappingSetting = "/Amazon/Preferences/Editor/AngleSnapping";
constexpr AZStd::string_view AngleSizeSetting = "/Amazon/Preferences/Editor/AngleSize";
constexpr AZStd::string_view ShowGridSetting = "/Amazon/Preferences/Editor/ShowGrid";
+ constexpr AZStd::string_view StickySelectSetting = "/Amazon/Preferences/Editor/StickySelect";
constexpr AZStd::string_view ManipulatorLineBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/LineBoundWidth";
constexpr AZStd::string_view ManipulatorCircleBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/CircleBoundWidth";
constexpr AZStd::string_view CameraTranslateSpeedSetting = "/Amazon/Preferences/Editor/Camera/TranslateSpeed";
@@ -158,6 +159,16 @@ namespace SandboxEditor
SetRegistry(ShowGridSetting, showing);
}
+ bool StickySelectEnabled()
+ {
+ return GetRegistry(StickySelectSetting, false);
+ }
+
+ void SetStickySelectEnabled(const bool enabled)
+ {
+ SetRegistry(StickySelectSetting, enabled);
+ }
+
float ManipulatorLineBoundWidth()
{
return aznumeric_cast(GetRegistry(ManipulatorLineBoundWidthSetting, 0.1));
diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h
index 8aeeee1384..20d397a29e 100644
--- a/Code/Editor/EditorViewportSettings.h
+++ b/Code/Editor/EditorViewportSettings.h
@@ -47,6 +47,9 @@ namespace SandboxEditor
SANDBOX_API bool ShowingGrid();
SANDBOX_API void SetShowingGrid(bool showing);
+ SANDBOX_API bool StickySelectEnabled();
+ SANDBOX_API void SetStickySelectEnabled(bool enabled);
+
SANDBOX_API float ManipulatorLineBoundWidth();
SANDBOX_API void SetManipulatorLineBoundWidth(float lineBoundWidth);
diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp
index f009fe7602..dad6734428 100644
--- a/Code/Editor/EditorViewportWidget.cpp
+++ b/Code/Editor/EditorViewportWidget.cpp
@@ -744,11 +744,15 @@ void EditorViewportWidget::RenderAll()
{
namespace AztfVi = AzToolsFramework::ViewportInteraction;
+ AztfVi::KeyboardModifiers keyboardModifiers;
+ AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
+ keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
+
m_debugDisplay->DepthTestOff();
m_manipulatorManager->DrawManipulators(
*m_debugDisplay, GetCameraState(),
BuildMouseInteractionInternal(
- AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), QueryKeyboardModifiers(),
+ AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), keyboardModifiers,
BuildMousePick(WidgetToViewport(mapFromGlobal(QCursor::pos())))));
m_debugDisplay->DepthTestOn();
}
@@ -959,12 +963,13 @@ QWidget* EditorViewportWidget::GetWidgetForViewportContextMenu()
bool EditorViewportWidget::ShowingWorldSpace()
{
- return QueryKeyboardModifiers().Shift();
-}
+ namespace AztfVi = AzToolsFramework::ViewportInteraction;
-AzToolsFramework::ViewportInteraction::KeyboardModifiers EditorViewportWidget::QueryKeyboardModifiers()
-{
- return AzToolsFramework::ViewportInteraction::BuildKeyboardModifiers(QGuiApplication::queryKeyboardModifiers());
+ AztfVi::KeyboardModifiers keyboardModifiers;
+ AztfVi::EditorModifierKeyRequestBus::BroadcastResult(
+ keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers);
+
+ return keyboardModifiers.Shift();
}
void EditorViewportWidget::SetViewportId(int id)
@@ -1039,7 +1044,6 @@ void EditorViewportWidget::ConnectViewportInteractionRequestBus()
{
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
- AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
m_viewportUi.ConnectViewportUiBus(GetViewportId());
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusConnect();
@@ -1050,7 +1054,6 @@ void EditorViewportWidget::DisconnectViewportInteractionRequestBus()
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusDisconnect();
m_viewportUi.DisconnectViewportUiBus();
- AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusDisconnect();
}
@@ -2425,7 +2428,7 @@ void EditorViewportWidget::RestoreViewportAfterGameMode()
}
else
{
- AZ_Error("CryLegacy", false, "Not restoring the editor viewport camera is currently unsupported");
+ AZ_Warning("CryLegacy", false, "Not restoring the editor viewport camera is currently unsupported");
SetViewTM(preGameModeViewTM);
}
}
@@ -2522,6 +2525,11 @@ float EditorViewportSettings::ManipulatorCircleBoundWidth() const
return SandboxEditor::ManipulatorCircleBoundWidth();
}
+bool EditorViewportSettings::StickySelectEnabled() const
+{
+ return SandboxEditor::StickySelectEnabled();
+}
+
AZ_CVAR_EXTERNED(bool, ed_previewGameInFullscreen_once);
bool EditorViewportWidget::ShouldPreviewFullscreen() const
diff --git a/Code/Editor/EditorViewportWidget.h b/Code/Editor/EditorViewportWidget.h
index c4a8e9fcca..49930a2a13 100644
--- a/Code/Editor/EditorViewportWidget.h
+++ b/Code/Editor/EditorViewportWidget.h
@@ -77,6 +77,7 @@ struct EditorViewportSettings : public AzToolsFramework::ViewportInteraction::Vi
float AngleStep() const override;
float ManipulatorLineBoundWidth() const override;
float ManipulatorCircleBoundWidth() const override;
+ bool StickySelectEnabled() const override;
};
// EditorViewportWidget window
@@ -91,7 +92,6 @@ class SANDBOX_API EditorViewportWidget final
, private AzFramework::InputSystemCursorConstraintRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler
- , private AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
, private AZ::RPI::SceneNotificationBus::Handler
{
@@ -211,9 +211,6 @@ private:
// EditorEntityViewportInteractionRequestBus overrides ...
void FindVisibleEntities(AZStd::vector& visibleEntities) override;
- // EditorModifierKeyRequestBus overrides ...
- AzToolsFramework::ViewportInteraction::KeyboardModifiers QueryKeyboardModifiers() override;
-
// Camera::EditorCameraRequestBus overrides ...
void SetViewFromEntityPerspective(const AZ::EntityId& entityId) override;
void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override;
diff --git a/Code/Editor/Export/ExportManager.h b/Code/Editor/Export/ExportManager.h
index be81591e56..14318be957 100644
--- a/Code/Editor/Export/ExportManager.h
+++ b/Code/Editor/Export/ExportManager.h
@@ -36,8 +36,8 @@ namespace Export
public:
CMesh();
- virtual int GetFaceCount() const { return static_cast(m_faces.size()); }
- virtual const Face* GetFaceBuffer() const { return m_faces.size() ? &m_faces[0] : 0; }
+ int GetFaceCount() const override { return static_cast(m_faces.size()); }
+ const Face* GetFaceBuffer() const override { return !m_faces.empty() ? &m_faces[0] : nullptr; }
private:
std::vector m_faces;
@@ -54,13 +54,13 @@ namespace Export
CObject(const char* pName);
int GetVertexCount() const override { return static_cast(m_vertices.size()); }
- const Vector3D* GetVertexBuffer() const override { return m_vertices.size() ? &m_vertices[0] : nullptr; }
+ const Vector3D* GetVertexBuffer() const override { return !m_vertices.empty() ? &m_vertices[0] : nullptr; }
int GetNormalCount() const override { return static_cast(m_normals.size()); }
- const Vector3D* GetNormalBuffer() const override { return m_normals.size() ? &m_normals[0] : nullptr; }
+ const Vector3D* GetNormalBuffer() const override { return !m_normals.empty() ? &m_normals[0] : nullptr; }
int GetTexCoordCount() const override { return static_cast(m_texCoords.size()); }
- const UV* GetTexCoordBuffer() const override { return m_texCoords.size() ? &m_texCoords[0] : nullptr; }
+ const UV* GetTexCoordBuffer() const override { return !m_texCoords.empty() ? &m_texCoords[0] : nullptr; }
int GetMeshCount() const override { return static_cast(m_meshes.size()); }
Mesh* GetMesh(int index) const override { return m_meshes[index]; }
@@ -68,9 +68,9 @@ namespace Export
size_t MeshHash() const override{return m_MeshHash; }
void SetMaterialName(const char* pName);
- virtual int GetEntityAnimationDataCount() const {return static_cast(m_entityAnimData.size()); }
- virtual const EntityAnimData* GetEntityAnimationData(int index) const {return &m_entityAnimData[index]; }
- virtual void SetEntityAnimationData(EntityAnimData entityData){ m_entityAnimData.push_back(entityData); };
+ int GetEntityAnimationDataCount() const override {return static_cast(m_entityAnimData.size()); }
+ const EntityAnimData* GetEntityAnimationData(int index) const override {return &m_entityAnimData[index]; }
+ void SetEntityAnimationData(EntityAnimData entityData) override{ m_entityAnimData.push_back(entityData); };
void SetLastPtr(CBaseObject* pObject){m_pLastObject = pObject; };
CBaseObject* GetLastObjectPtr(){return m_pLastObject; };
@@ -92,9 +92,11 @@ namespace Export
: public IData
{
public:
- virtual int GetObjectCount() const { return static_cast(m_objects.size()); }
- virtual Object* GetObject(int index) const { return m_objects[index]; }
- virtual Object* AddObject(const char* objectName);
+ virtual ~CData() = default;
+
+ int GetObjectCount() const override { return static_cast(m_objects.size()); }
+ Object* GetObject(int index) const override { return m_objects[index]; }
+ Object* AddObject(const char* objectName) override;
void Clear();
private:
@@ -117,7 +119,7 @@ public:
//! Register exporter
//! return true if succeed, otherwise false
- virtual bool RegisterExporter(IExporter* pExporter);
+ bool RegisterExporter(IExporter* pExporter) override;
//! Export specified geometry
//! return true if succeed, otherwise false
@@ -139,15 +141,15 @@ public:
//! Exports the stat obj to the obj file specified
//! returns true if succeeded, otherwise false
- virtual bool ExportSingleStatObj(IStatObj* pStatObj, const char* filename);
+ bool ExportSingleStatObj(IStatObj* pStatObj, const char* filename) override;
void SetBakedKeysSequenceExport(bool bBaked){m_bBakedKeysSequenceExport = bBaked; };
void SaveNodeKeysTimeToXML();
private:
- void AddMesh(Export::CObject* pObj, const IIndexedMesh* pIndMesh, Matrix34A* pTm = 0);
- bool AddStatObj(Export::CObject* pObj, IStatObj* pStatObj, Matrix34A* pTm = 0);
+ void AddMesh(Export::CObject* pObj, const IIndexedMesh* pIndMesh, Matrix34A* pTm = nullptr);
+ bool AddStatObj(Export::CObject* pObj, IStatObj* pStatObj, Matrix34A* pTm = nullptr);
bool AddMeshes(Export::CObject* pObj);
bool AddObject(CBaseObject* pBaseObj);
void SolveHierarchy();
diff --git a/Code/Editor/GameExporter.cpp b/Code/Editor/GameExporter.cpp
index 00dc3d8de1..9315505e08 100644
--- a/Code/Editor/GameExporter.cpp
+++ b/Code/Editor/GameExporter.cpp
@@ -432,25 +432,6 @@ void CGameExporter::ExportFileList(const QString& path, const QString& levelName
newFileNode->setAttr("src", handle.m_filename.data());
newFileNode->setAttr("dest", handle.m_filename.data());
newFileNode->setAttr("size", handle.m_fileDesc.nSize);
-
- unsigned char md5[16];
- AZStd::string filenameToHash = GetIEditor()->GetGameEngine()->GetLevelPath().toUtf8().data();
- filenameToHash += "/";
- filenameToHash += AZStd::string{ handle.m_filename.data(), handle.m_filename.size() };
- if (gEnv->pCryPak->ComputeMD5(filenameToHash.data(), md5))
- {
- char md5string[33];
- sprintf_s(md5string, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- md5[0], md5[1], md5[2], md5[3],
- md5[4], md5[5], md5[6], md5[7],
- md5[8], md5[9], md5[10], md5[11],
- md5[12], md5[13], md5[14], md5[15]);
- newFileNode->setAttr("md5", md5string);
- }
- else
- {
- newFileNode->setAttr("md5", "");
- }
}
}
} while (handle = gEnv->pCryPak->FindNext(handle));
diff --git a/Code/Editor/IEditorImpl.h b/Code/Editor/IEditorImpl.h
index 762dd1db11..26701edec2 100644
--- a/Code/Editor/IEditorImpl.h
+++ b/Code/Editor/IEditorImpl.h
@@ -79,70 +79,70 @@ public:
void SetGameEngine(CGameEngine* ge);
- void DeleteThis() { delete this; };
- IEditorClassFactory* GetClassFactory();
- CEditorCommandManager* GetCommandManager() { return m_pCommandManager; };
- ICommandManager* GetICommandManager() { return m_pCommandManager; }
- void ExecuteCommand(const char* sCommand, ...);
- void ExecuteCommand(const QString& command);
- void SetDocument(CCryEditDoc* pDoc);
- CCryEditDoc* GetDocument() const;
+ void DeleteThis() override { delete this; };
+ IEditorClassFactory* GetClassFactory() override;
+ CEditorCommandManager* GetCommandManager() override { return m_pCommandManager; };
+ ICommandManager* GetICommandManager() override { return m_pCommandManager; }
+ void ExecuteCommand(const char* sCommand, ...) override;
+ void ExecuteCommand(const QString& command) override;
+ void SetDocument(CCryEditDoc* pDoc) override;
+ CCryEditDoc* GetDocument() const override;
bool IsLevelLoaded() const override;
- void SetModifiedFlag(bool modified = true);
- void SetModifiedModule(EModifiedModule eModifiedModule, bool boSet = true);
- bool IsLevelExported() const;
- bool SetLevelExported(bool boExported = true);
+ void SetModifiedFlag(bool modified = true) override;
+ void SetModifiedModule(EModifiedModule eModifiedModule, bool boSet = true) override;
+ bool IsLevelExported() const override;
+ bool SetLevelExported(bool boExported = true) override;
void InitFinished();
- bool IsModified();
- bool IsInitialized() const{ return m_bInitialized; }
- bool SaveDocument();
- ISystem* GetSystem();
- void WriteToConsole(const char* string) { CLogFile::WriteLine(string); };
- void WriteToConsole(const QString& string) { CLogFile::WriteLine(string); };
+ bool IsModified() override;
+ bool IsInitialized() const override{ return m_bInitialized; }
+ bool SaveDocument() override;
+ ISystem* GetSystem() override;
+ void WriteToConsole(const char* string) override { CLogFile::WriteLine(string); };
+ void WriteToConsole(const QString& string) override { CLogFile::WriteLine(string); };
// Change the message in the status bar
- void SetStatusText(const QString& pszString);
- virtual IMainStatusBar* GetMainStatusBar() override;
- bool ShowConsole([[maybe_unused]] bool show)
+ void SetStatusText(const QString& pszString) override;
+ IMainStatusBar* GetMainStatusBar() override;
+ bool ShowConsole([[maybe_unused]] bool show) override
{
//if (AfxGetMainWnd())return ((CMainFrame *) (AfxGetMainWnd()))->ShowConsole(show);
return false;
}
- void SetConsoleVar(const char* var, float value);
- float GetConsoleVar(const char* var);
+ void SetConsoleVar(const char* var, float value) override;
+ float GetConsoleVar(const char* var) override;
//! Query main window of the editor
QMainWindow* GetEditorMainWindow() const override
{
return MainWindow::instance();
};
- QString GetPrimaryCDFolder();
+ QString GetPrimaryCDFolder() override;
QString GetLevelName() override;
- QString GetLevelFolder();
- QString GetLevelDataFolder();
- QString GetSearchPath(EEditorPathName path);
- QString GetResolvedUserFolder();
- bool ExecuteConsoleApp(const QString& CommandLine, QString& OutputText, bool bNoTimeOut = false, bool bShowWindow = false);
- virtual bool IsInGameMode() override;
- virtual void SetInGameMode(bool inGame) override;
- virtual bool IsInSimulationMode() override;
- virtual bool IsInTestMode() override;
- virtual bool IsInPreviewMode() override;
- virtual bool IsInConsolewMode() override;
- virtual bool IsInLevelLoadTestMode() override;
- virtual bool IsInMatEditMode() override { return m_bMatEditMode; }
+ QString GetLevelFolder() override;
+ QString GetLevelDataFolder() override;
+ QString GetSearchPath(EEditorPathName path) override;
+ QString GetResolvedUserFolder() override;
+ bool ExecuteConsoleApp(const QString& CommandLine, QString& OutputText, bool bNoTimeOut = false, bool bShowWindow = false) override;
+ bool IsInGameMode() override;
+ void SetInGameMode(bool inGame) override;
+ bool IsInSimulationMode() override;
+ bool IsInTestMode() override;
+ bool IsInPreviewMode() override;
+ bool IsInConsolewMode() override;
+ bool IsInLevelLoadTestMode() override;
+ bool IsInMatEditMode() override { return m_bMatEditMode; }
//! Enables/Disable updates of editor.
- void EnableUpdate(bool enable) { m_bUpdates = enable; };
+ void EnableUpdate(bool enable) override { m_bUpdates = enable; };
//! Enable/Disable accelerator table, (Enabled by default).
- void EnableAcceleratos(bool bEnable);
- CGameEngine* GetGameEngine() { return m_pGameEngine; };
- CDisplaySettings* GetDisplaySettings() { return m_pDisplaySettings; };
- const SGizmoParameters& GetGlobalGizmoParameters();
- CBaseObject* NewObject(const char* typeName, const char* fileName = "", const char* name = "", float x = 0.0f, float y = 0.0f, float z = 0.0f, bool modifyDoc = true);
- void DeleteObject(CBaseObject* obj);
- CBaseObject* CloneObject(CBaseObject* obj);
- IObjectManager* GetObjectManager();
+ void EnableAcceleratos(bool bEnable) override;
+ CGameEngine* GetGameEngine() override { return m_pGameEngine; };
+ CDisplaySettings* GetDisplaySettings() override { return m_pDisplaySettings; };
+ const SGizmoParameters& GetGlobalGizmoParameters() override;
+ CBaseObject* NewObject(const char* typeName, const char* fileName = "", const char* name = "", float x = 0.0f, float y = 0.0f, float z = 0.0f, bool modifyDoc = true) override;
+ void DeleteObject(CBaseObject* obj) override;
+ CBaseObject* CloneObject(CBaseObject* obj) override;
+ IObjectManager* GetObjectManager() override;
// This will return a null pointer if CrySystem is not loaded before
// Global Sandbox Settings are loaded from the registry before CrySystem
// At that stage GetSettingsManager will return null and xml node in
@@ -150,27 +150,27 @@ public:
// After m_IEditor is created and CrySystem loaded, it is possible
// to feed memory node with all necessary data needed for export
// (gSettings.Load() and CXTPDockingPaneManager/CXTPDockingPaneLayout Sandbox layout management)
- CSettingsManager* GetSettingsManager();
- CSelectionGroup* GetSelection();
- int ClearSelection();
- CBaseObject* GetSelectedObject();
- void SelectObject(CBaseObject* obj);
- void LockSelection(bool bLock);
- bool IsSelectionLocked();
+ CSettingsManager* GetSettingsManager() override;
+ CSelectionGroup* GetSelection() override;
+ int ClearSelection() override;
+ CBaseObject* GetSelectedObject() override;
+ void SelectObject(CBaseObject* obj) override;
+ void LockSelection(bool bLock) override;
+ bool IsSelectionLocked() override;
- IDataBaseManager* GetDBItemManager(EDataBaseItemType itemType);
- CMusicManager* GetMusicManager() { return m_pMusicManager; };
+ IDataBaseManager* GetDBItemManager(EDataBaseItemType itemType) override;
+ CMusicManager* GetMusicManager() override { return m_pMusicManager; };
IEditorFileMonitor* GetFileMonitor() override;
void RegisterEventLoopHook(IEventLoopHook* pHook) override;
void UnregisterEventLoopHook(IEventLoopHook* pHook) override;
- IIconManager* GetIconManager();
- float GetTerrainElevation(float x, float y);
- Editor::EditorQtApplication* GetEditorQtApplication() { return m_QtApplication; }
+ IIconManager* GetIconManager() override;
+ float GetTerrainElevation(float x, float y) override;
+ Editor::EditorQtApplication* GetEditorQtApplication() override { return m_QtApplication; }
const QColor& GetColorByName(const QString& name) override;
//////////////////////////////////////////////////////////////////////////
- IMovieSystem* GetMovieSystem()
+ IMovieSystem* GetMovieSystem() override
{
if (m_pSystem)
{
@@ -179,37 +179,37 @@ public:
return nullptr;
};
- CPluginManager* GetPluginManager() { return m_pPluginManager; }
- CViewManager* GetViewManager();
- CViewport* GetActiveView();
- void SetActiveView(CViewport* viewport);
+ CPluginManager* GetPluginManager() override { return m_pPluginManager; }
+ CViewManager* GetViewManager() override;
+ CViewport* GetActiveView() override;
+ void SetActiveView(CViewport* viewport) override;
- CLevelIndependentFileMan* GetLevelIndependentFileMan() { return m_pLevelIndependentFileMan; }
+ CLevelIndependentFileMan* GetLevelIndependentFileMan() override { return m_pLevelIndependentFileMan; }
- void UpdateViews(int flags, const AABB* updateRegion);
- void ResetViews();
- void ReloadTrackView();
- Vec3 GetMarkerPosition() { return m_marker; };
- void SetMarkerPosition(const Vec3& pos) { m_marker = pos; };
- void SetSelectedRegion(const AABB& box);
- void GetSelectedRegion(AABB& box);
+ void UpdateViews(int flags, const AABB* updateRegion) override;
+ void ResetViews() override;
+ void ReloadTrackView() override;
+ Vec3 GetMarkerPosition() override { return m_marker; };
+ void SetMarkerPosition(const Vec3& pos) override { m_marker = pos; };
+ void SetSelectedRegion(const AABB& box) override;
+ void GetSelectedRegion(AABB& box) override;
bool AddToolbarItem(uint8 iId, IUIEvent* pIHandler);
- void SetDataModified();
- void SetOperationMode(EOperationMode mode);
- EOperationMode GetOperationMode();
+ void SetDataModified() override;
+ void SetOperationMode(EOperationMode mode) override;
+ EOperationMode GetOperationMode() override;
- ITransformManipulator* ShowTransformManipulator(bool bShow);
- ITransformManipulator* GetTransformManipulator();
- void SetAxisConstraints(AxisConstrains axis);
- AxisConstrains GetAxisConstrains();
- void SetAxisVectorLock(bool bAxisVectorLock) { m_bAxisVectorLock = bAxisVectorLock; }
- bool IsAxisVectorLocked() { return m_bAxisVectorLock; }
- void SetTerrainAxisIgnoreObjects(bool bIgnore);
- bool IsTerrainAxisIgnoreObjects();
- void SetReferenceCoordSys(RefCoordSys refCoords);
- RefCoordSys GetReferenceCoordSys();
- XmlNodeRef FindTemplate(const QString& templateName);
- void AddTemplate(const QString& templateName, XmlNodeRef& tmpl);
+ ITransformManipulator* ShowTransformManipulator(bool bShow) override;
+ ITransformManipulator* GetTransformManipulator() override;
+ void SetAxisConstraints(AxisConstrains axis) override;
+ AxisConstrains GetAxisConstrains() override;
+ void SetAxisVectorLock(bool bAxisVectorLock) override { m_bAxisVectorLock = bAxisVectorLock; }
+ bool IsAxisVectorLocked() override { return m_bAxisVectorLock; }
+ void SetTerrainAxisIgnoreObjects(bool bIgnore) override;
+ bool IsTerrainAxisIgnoreObjects() override;
+ void SetReferenceCoordSys(RefCoordSys refCoords) override;
+ RefCoordSys GetReferenceCoordSys() override;
+ XmlNodeRef FindTemplate(const QString& templateName) override;
+ void AddTemplate(const QString& templateName, XmlNodeRef& tmpl) override;
const QtViewPane* OpenView(QString sViewClassName, bool reuseOpened = true) override;
@@ -220,87 +220,87 @@ public:
*/
QWidget* FindView(QString viewClassName) override;
- bool CloseView(const char* sViewClassName);
- bool SetViewFocus(const char* sViewClassName);
+ bool CloseView(const char* sViewClassName) override;
+ bool SetViewFocus(const char* sViewClassName) override;
- virtual QWidget* OpenWinWidget(WinWidgetId openId) override;
- virtual WinWidget::WinWidgetManager* GetWinWidgetManager() const override;
+ QWidget* OpenWinWidget(WinWidgetId openId) override;
+ WinWidget::WinWidgetManager* GetWinWidgetManager() const override;
// close ALL panels related to classId, used when unloading plugins.
- void CloseView(const GUID& classId);
+ void CloseView(const GUID& classId) override;
bool SelectColor(QColor &color, QWidget *parent = 0) override;
void Update();
- SFileVersion GetFileVersion() { return m_fileVersion; };
- SFileVersion GetProductVersion() { return m_productVersion; };
+ SFileVersion GetFileVersion() override { return m_fileVersion; };
+ SFileVersion GetProductVersion() override { return m_productVersion; };
//! Get shader enumerator.
- CUndoManager* GetUndoManager() { return m_pUndoManager; };
- void BeginUndo();
- void RestoreUndo(bool undo);
- void AcceptUndo(const QString& name);
- void CancelUndo();
- void SuperBeginUndo();
- void SuperAcceptUndo(const QString& name);
- void SuperCancelUndo();
- void SuspendUndo();
- void ResumeUndo();
- void Undo();
- void Redo();
- bool IsUndoRecording();
- bool IsUndoSuspended();
- void RecordUndo(IUndoObject* obj);
- bool FlushUndo(bool isShowMessage = false);
- bool ClearLastUndoSteps(int steps);
- bool ClearRedoStack();
+ CUndoManager* GetUndoManager() override { return m_pUndoManager; };
+ void BeginUndo() override;
+ void RestoreUndo(bool undo) override;
+ void AcceptUndo(const QString& name) override;
+ void CancelUndo() override;
+ void SuperBeginUndo() override;
+ void SuperAcceptUndo(const QString& name) override;
+ void SuperCancelUndo() override;
+ void SuspendUndo() override;
+ void ResumeUndo() override;
+ void Undo() override;
+ void Redo() override;
+ bool IsUndoRecording() override;
+ bool IsUndoSuspended() override;
+ void RecordUndo(IUndoObject* obj) override;
+ bool FlushUndo(bool isShowMessage = false) override;
+ bool ClearLastUndoSteps(int steps) override;
+ bool ClearRedoStack() override;
//! Retrieve current animation context.
- CAnimationContext* GetAnimation();
+ CAnimationContext* GetAnimation() override;
CTrackViewSequenceManager* GetSequenceManager() override;
ITrackViewSequenceManager* GetSequenceManagerInterface() override;
- CToolBoxManager* GetToolBoxManager() { return m_pToolBoxManager; };
- IErrorReport* GetErrorReport() { return m_pErrorReport; }
- IErrorReport* GetLastLoadedLevelErrorReport() { return m_pLasLoadedLevelErrorReport; }
+ CToolBoxManager* GetToolBoxManager() override { return m_pToolBoxManager; };
+ IErrorReport* GetErrorReport() override { return m_pErrorReport; }
+ IErrorReport* GetLastLoadedLevelErrorReport() override { return m_pLasLoadedLevelErrorReport; }
void StartLevelErrorReportRecording() override;
- void CommitLevelErrorReport() {SAFE_DELETE(m_pLasLoadedLevelErrorReport); m_pLasLoadedLevelErrorReport = new CErrorReport(*m_pErrorReport); }
- virtual IFileUtil* GetFileUtil() override { return m_pFileUtil; }
- void Notify(EEditorNotifyEvent event);
- void NotifyExcept(EEditorNotifyEvent event, IEditorNotifyListener* listener);
- void RegisterNotifyListener(IEditorNotifyListener* listener);
- void UnregisterNotifyListener(IEditorNotifyListener* listener);
+ void CommitLevelErrorReport() override {SAFE_DELETE(m_pLasLoadedLevelErrorReport); m_pLasLoadedLevelErrorReport = new CErrorReport(*m_pErrorReport); }
+ IFileUtil* GetFileUtil() override { return m_pFileUtil; }
+ void Notify(EEditorNotifyEvent event) override;
+ void NotifyExcept(EEditorNotifyEvent event, IEditorNotifyListener* listener) override;
+ void RegisterNotifyListener(IEditorNotifyListener* listener) override;
+ void UnregisterNotifyListener(IEditorNotifyListener* listener) override;
//! Register document notifications listener.
- void RegisterDocListener(IDocListener* listener);
+ void RegisterDocListener(IDocListener* listener) override;
//! Unregister document notifications listener.
- void UnregisterDocListener(IDocListener* listener);
+ void UnregisterDocListener(IDocListener* listener) override;
//! Retrieve interface to the source control.
- ISourceControl* GetSourceControl();
+ ISourceControl* GetSourceControl() override;
//! Retrieve true if source control is provided and enabled in settings
bool IsSourceControlAvailable() override;
//! Only returns true if source control is both available AND currently connected and functioning
bool IsSourceControlConnected() override;
//! Setup Material Editor mode
void SetMatEditMode(bool bIsMatEditMode);
- CUIEnumsDatabase* GetUIEnumsDatabase() { return m_pUIEnumsDatabase; };
- void AddUIEnums();
- void ReduceMemory();
+ CUIEnumsDatabase* GetUIEnumsDatabase() override { return m_pUIEnumsDatabase; };
+ void AddUIEnums() override;
+ void ReduceMemory() override;
// Get Export manager
- IExportManager* GetExportManager();
+ IExportManager* GetExportManager() override;
// Set current configuration spec of the editor.
- void SetEditorConfigSpec(ESystemConfigSpec spec, ESystemConfigPlatform platform);
- ESystemConfigSpec GetEditorConfigSpec() const;
- ESystemConfigPlatform GetEditorConfigPlatform() const;
- void ReloadTemplates();
+ void SetEditorConfigSpec(ESystemConfigSpec spec, ESystemConfigPlatform platform) override;
+ ESystemConfigSpec GetEditorConfigSpec() const override;
+ ESystemConfigPlatform GetEditorConfigPlatform() const override;
+ void ReloadTemplates() override;
void AddErrorMessage(const QString& text, const QString& caption);
- virtual void ShowStatusText(bool bEnable);
+ void ShowStatusText(bool bEnable) override;
void OnObjectContextMenuOpened(QMenu* pMenu, const CBaseObject* pObject);
- virtual void RegisterObjectContextMenuExtension(TContextMenuExtensionFunc func) override;
+ void RegisterObjectContextMenuExtension(TContextMenuExtensionFunc func) override;
- virtual SSystemGlobalEnvironment* GetEnv() override;
- virtual IBaseLibraryManager* GetMaterialManagerLibrary() override; // Vladimir@Conffx
- virtual IEditorMaterialManager* GetIEditorMaterialManager() override; // Vladimir@Conffx
- virtual IImageUtil* GetImageUtil() override; // Vladimir@conffx
- virtual SEditorSettings* GetEditorSettings() override;
- virtual IEditorPanelUtils* GetEditorPanelUtils() override;
- virtual ILogFile* GetLogFile() override { return m_pLogFile; }
+ SSystemGlobalEnvironment* GetEnv() override;
+ IBaseLibraryManager* GetMaterialManagerLibrary() override; // Vladimir@Conffx
+ IEditorMaterialManager* GetIEditorMaterialManager() override; // Vladimir@Conffx
+ IImageUtil* GetImageUtil() override; // Vladimir@conffx
+ SEditorSettings* GetEditorSettings() override;
+ IEditorPanelUtils* GetEditorPanelUtils() override;
+ ILogFile* GetLogFile() override { return m_pLogFile; }
void UnloadPlugins() override;
void LoadPlugins() override;
diff --git a/Code/Editor/Include/IEditorClassFactory.h b/Code/Editor/Include/IEditorClassFactory.h
index 0827dc96dc..dd47f803e2 100644
--- a/Code/Editor/Include/IEditorClassFactory.h
+++ b/Code/Editor/Include/IEditorClassFactory.h
@@ -14,8 +14,10 @@
#define CRYINCLUDE_EDITOR_INCLUDE_IEDITORCLASSFACTORY_H
#pragma once
+#include
#include
#include
+#include
#define DEFINE_UUID(l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
static const GUID uuid() { return { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }; }
@@ -34,7 +36,7 @@ struct IUnknown
#endif
#define __uuidof(T) T::uuid()
-#if defined(AZ_PLATFORM_LINUX)
+#if defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
# ifndef _REFGUID_DEFINED
# define _REFGUID_DEFINED
@@ -65,7 +67,7 @@ enum
};
#endif
-#endif // defined(AZ_PLATFORM_LINUX)
+#endif // defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
#include "SandboxAPI.h"
diff --git a/Code/Editor/LevelTreeModel.h b/Code/Editor/LevelTreeModel.h
index 4f0e36a311..7cc5cf5496 100644
--- a/Code/Editor/LevelTreeModel.h
+++ b/Code/Editor/LevelTreeModel.h
@@ -23,7 +23,7 @@ class LevelTreeModelFilter
Q_OBJECT
public:
explicit LevelTreeModelFilter(QObject* parent = nullptr);
- bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
void setFilterText(const QString&);
QVariant data(const QModelIndex& index, int role) const override;
private:
diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Android/tool_dependencies_android.cmake b/Code/Editor/Lib/Tests/Camera/editor_lib_camera_test_files.cmake
similarity index 85%
rename from Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Android/tool_dependencies_android.cmake
rename to Code/Editor/Lib/Tests/Camera/editor_lib_camera_test_files.cmake
index 5bf4d7cb7e..69d3e37f2d 100644
--- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Android/tool_dependencies_android.cmake
+++ b/Code/Editor/Lib/Tests/Camera/editor_lib_camera_test_files.cmake
@@ -6,5 +6,6 @@
#
#
-set(GEM_DEPENDENCIES
+set(FILES
+ test_EditorCamera.cpp
)
diff --git a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp
new file mode 100644
index 0000000000..affe5794cc
--- /dev/null
+++ b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace UnitTest
+{
+ class EditorCameraTestEnvironment : public AZ::Test::GemTestEnvironment
+ {
+ // AZ::Test::GemTestEnvironment overrides ...
+ void AddGemsAndComponents() override;
+ };
+
+ void EditorCameraTestEnvironment::AddGemsAndComponents()
+ {
+ AddDynamicModulePaths({ CAMERA_EDITOR_MODULE });
+ AddComponentDescriptors({ AzToolsFramework::Components::TransformComponent::CreateDescriptor() });
+ }
+
+ class EditorCameraFixture : public ::testing::Test
+ {
+ public:
+ AtomToolsFramework::ModularCameraViewportContext* m_cameraViewportContextView = nullptr;
+ AZStd::unique_ptr m_editorModularViewportCameraComposer;
+ AZStd::unique_ptr m_editorLibHandle;
+ AzFramework::ViewportControllerListPtr m_controllerList;
+ AZStd::unique_ptr m_entity;
+
+ static const AzFramework::ViewportId TestViewportId;
+
+ void SetUp() override
+ {
+ m_editorLibHandle = AZ::DynamicModuleHandle::Create("EditorLib");
+ [[maybe_unused]] const bool loaded = m_editorLibHandle->Load(true);
+ AZ_Assert(loaded, "EditorLib could not be loaded");
+
+ m_controllerList = AZStd::make_shared();
+ m_controllerList->RegisterViewportContext(TestViewportId);
+
+ m_entity = AZStd::make_unique();
+ m_entity->Init();
+ m_entity->CreateComponent();
+ m_entity->Activate();
+
+ m_editorModularViewportCameraComposer = AZStd::make_unique(TestViewportId);
+
+ auto controller = m_editorModularViewportCameraComposer->CreateModularViewportCameraController();
+ // set some overrides for the test
+ controller->SetCameraViewportContextBuilderCallback(
+ [this](AZStd::unique_ptr& cameraViewportContext) mutable
+ {
+ cameraViewportContext = AZStd::make_unique();
+ m_cameraViewportContextView = cameraViewportContext.get();
+ });
+
+ m_controllerList->Add(controller);
+ }
+
+ void TearDown() override
+ {
+ m_editorModularViewportCameraComposer.reset();
+ m_cameraViewportContextView = nullptr;
+ m_entity.reset();
+ m_editorLibHandle = {};
+ }
+ };
+
+ const AzFramework::ViewportId EditorCameraFixture::TestViewportId = AzFramework::ViewportId(1337);
+
+ TEST_F(EditorCameraFixture, ModularViewportCameraControllerReferenceFrameUpdatedWhenViewportEntityisChanged)
+ {
+ // Given
+ const auto entityTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
+ AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(10.0f, 5.0f, -2.0f));
+ AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformBus::Events::SetWorldTM, entityTransform);
+
+ // When
+ // imitate viewport entity changing
+ Camera::EditorCameraNotificationBus::Broadcast(
+ &Camera::EditorCameraNotificationBus::Events::OnViewportViewEntityChanged, m_entity->GetId());
+
+ // ensure the viewport updates after the viewport view entity change
+ const float deltaTime = 1.0f / 60.0f;
+ m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
+
+ // retrieve updated camera transform
+ const AZ::Transform cameraTransform = m_cameraViewportContextView->GetCameraTransform();
+
+ // Then
+ // camera transform matches that of the entity
+ EXPECT_THAT(cameraTransform, IsClose(entityTransform));
+ }
+
+ TEST_F(EditorCameraFixture, ReferenceFrameRemainsIdentityAfterExternalCameraTransformChangeWhenNotSet)
+ {
+ // Given
+ m_cameraViewportContextView->SetCameraTransform(AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 20.0f, 30.0f)));
+
+ // When
+ AZ::Transform referenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
+ referenceFrame, TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
+
+ // Then
+ // reference frame is still the identity
+ EXPECT_THAT(referenceFrame, IsClose(AZ::Transform::CreateIdentity()));
+ }
+
+ TEST_F(EditorCameraFixture, ExternalCameraTransformChangeWhenReferenceFrameIsSetUpdatesReferenceFrame)
+ {
+ // Given
+ const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
+ AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
+
+ const AZ::Transform nextTransform = AZ::Transform::CreateTranslation(AZ::Vector3(10.0f, 20.0f, 30.0f));
+ m_cameraViewportContextView->SetCameraTransform(nextTransform);
+
+ // When
+ AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
+ currentReferenceFrame, TestViewportId,
+ &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
+
+ // Then
+ EXPECT_THAT(currentReferenceFrame, IsClose(nextTransform));
+ }
+
+ TEST_F(EditorCameraFixture, ReferenceFrameReturnedToIdentityAfterClear)
+ {
+ // Given
+ const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
+ AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
+
+ // When
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
+
+ AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
+ currentReferenceFrame, TestViewportId,
+ &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
+
+ // Then
+ EXPECT_THAT(currentReferenceFrame, IsClose(AZ::Transform::CreateIdentity()));
+ }
+
+ TEST_F(EditorCameraFixture, InterpolateToTransform)
+ {
+ // When
+ AZ::Transform transformToInterpolateTo = AZ::Transform::CreateFromQuaternionAndTranslation(
+ AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
+ transformToInterpolateTo, 0.0f);
+
+ // simulate interpolation
+ m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
+ m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
+
+ const auto finalTransform = m_cameraViewportContextView->GetCameraTransform();
+
+ // Then
+ EXPECT_THAT(finalTransform, IsClose(transformToInterpolateTo));
+ }
+
+ TEST_F(EditorCameraFixture, InterpolateToTransformWithReferenceSpaceSet)
+ {
+ // Given
+ const AZ::Transform referenceFrame = AZ::Transform::CreateFromQuaternionAndTranslation(
+ AZ::Quaternion::CreateRotationX(AZ::DegToRad(90.0f)), AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, referenceFrame);
+
+ AZ::Transform transformToInterpolateTo = AZ::Transform::CreateFromQuaternionAndTranslation(
+ AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
+
+ // When
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
+ TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
+ transformToInterpolateTo, 0.0f);
+
+ // simulate interpolation
+ m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
+ m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
+
+ AZ::Transform currentReferenceFrame = AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f));
+ AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
+ currentReferenceFrame, TestViewportId,
+ &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::GetReferenceFrame);
+
+ const auto finalTransform = m_cameraViewportContextView->GetCameraTransform();
+
+ // Then
+ EXPECT_THAT(finalTransform, IsClose(transformToInterpolateTo));
+ EXPECT_THAT(currentReferenceFrame, IsClose(AZ::Transform::CreateIdentity()));
+ }
+} // namespace UnitTest
+
+// required to support running integration tests with the Camera Gem
+AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv)
+{
+ ::testing::InitGoogleMock(&argc, argv);
+ AZ::Test::printUnusedParametersWarning(argc, argv);
+ AZ::Test::addTestEnvironments({ new UnitTest::EditorCameraTestEnvironment() });
+ int result = RUN_ALL_TESTS();
+ return result;
+}
+
+IMPLEMENT_TEST_EXECUTABLE_MAIN();
diff --git a/Code/Editor/Lib/Tests/IEditorMock.h b/Code/Editor/Lib/Tests/IEditorMock.h
index cb01757b9c..390ffebe79 100644
--- a/Code/Editor/Lib/Tests/IEditorMock.h
+++ b/Code/Editor/Lib/Tests/IEditorMock.h
@@ -25,6 +25,8 @@ public:
}
public:
+ virtual ~CEditorMock() = default;
+
MOCK_METHOD0(DeleteThis, void());
MOCK_METHOD0(GetSystem, ISystem*());
MOCK_METHOD0(GetClassFactory, IEditorClassFactory* ());
diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp
index ce5564c7f6..157291cfc2 100644
--- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp
+++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp
@@ -58,28 +58,6 @@ namespace UnitTest
return true;
}
- class TestModularCameraViewportContextImpl : public AtomToolsFramework::ModularCameraViewportContext
- {
- public:
- AZ::Transform GetCameraTransform() const override
- {
- return m_cameraTransform;
- }
-
- void SetCameraTransform(const AZ::Transform& transform) override
- {
- m_cameraTransform = transform;
- }
-
- void ConnectViewMatrixChangedHandler(AZ::RPI::ViewportContext::MatrixChangedEvent::Handler&) override
- {
- // noop
- }
-
- private:
- AZ::Transform m_cameraTransform = AZ::Transform::CreateIdentity();
- };
-
class ModularViewportCameraControllerFixture : public AllocatorsTestFixture
{
public:
@@ -146,7 +124,7 @@ namespace UnitTest
controller->SetCameraViewportContextBuilderCallback(
[this](AZStd::unique_ptr& cameraViewportContext)
{
- cameraViewportContext = AZStd::make_unique();
+ cameraViewportContext = AZStd::make_unique();
m_cameraViewportContextView = cameraViewportContext.get();
});
diff --git a/Code/Editor/Objects/AxisGizmo.h b/Code/Editor/Objects/AxisGizmo.h
index dfd35388b6..bab667a629 100644
--- a/Code/Editor/Objects/AxisGizmo.h
+++ b/Code/Editor/Objects/AxisGizmo.h
@@ -35,21 +35,21 @@ public:
//////////////////////////////////////////////////////////////////////////
// Ovverides from CGizmo
//////////////////////////////////////////////////////////////////////////
- virtual void GetWorldBounds(AABB& bbox);
- virtual void Display(DisplayContext& dc);
- virtual bool HitTest(HitContext& hc);
- virtual const Matrix34& GetMatrix() const;
+ void GetWorldBounds(AABB& bbox) override;
+ void Display(DisplayContext& dc) override;
+ bool HitTest(HitContext& hc) override;
+ const Matrix34& GetMatrix() const override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// ITransformManipulator implementation.
//////////////////////////////////////////////////////////////////////////
- virtual Matrix34 GetTransformation(RefCoordSys coordSys, IDisplayViewport* view = nullptr) const;
- virtual void SetTransformation(RefCoordSys coordSys, const Matrix34& tm);
- virtual bool HitTestManipulator(HitContext& hc);
- virtual bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int nFlags);
- virtual void SetAlwaysUseLocal(bool on)
+ Matrix34 GetTransformation(RefCoordSys coordSys, IDisplayViewport* view = nullptr) const override;
+ void SetTransformation(RefCoordSys coordSys, const Matrix34& tm) override;
+ bool HitTestManipulator(HitContext& hc) override;
+ bool MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, int nFlags) override;
+ void SetAlwaysUseLocal(bool on) override
{ m_bAlwaysUseLocal = on; }
//////////////////////////////////////////////////////////////////////////
diff --git a/Code/Editor/Objects/BaseObject.h b/Code/Editor/Objects/BaseObject.h
index ea58b4e78d..3865696ecb 100644
--- a/Code/Editor/Objects/BaseObject.h
+++ b/Code/Editor/Objects/BaseObject.h
@@ -712,7 +712,7 @@ protected:
// May be overridden in derived classes to handle helpers scaling.
//////////////////////////////////////////////////////////////////////////
virtual void SetHelperScale([[maybe_unused]] float scale) {};
- virtual float GetHelperScale() { return 1; };
+ virtual float GetHelperScale() { return 1.0f; };
void SetNameInternal(const QString& name) { m_name = name; }
@@ -743,9 +743,6 @@ private:
//! Only called once after creation by ObjectManager.
void SetClassDesc(CObjectClassDesc* classDesc);
- // From CObject, (not implemented)
- virtual void Serialize([[maybe_unused]] CArchive& ar) {};
-
EScaleWarningLevel GetScaleWarningLevel() const;
ERotationWarningLevel GetRotationWarningLevel() const;
diff --git a/Code/Editor/Objects/EntityObject.h b/Code/Editor/Objects/EntityObject.h
index d5600d15b7..dcc6ff7b22 100644
--- a/Code/Editor/Objects/EntityObject.h
+++ b/Code/Editor/Objects/EntityObject.h
@@ -82,14 +82,14 @@ public:
// Overrides from CBaseObject.
//////////////////////////////////////////////////////////////////////////
//! Return type name of Entity.
- QString GetTypeDescription() const { return GetEntityClass(); };
+ QString GetTypeDescription() const override { return GetEntityClass(); };
//////////////////////////////////////////////////////////////////////////
- bool IsSameClass(CBaseObject* obj);
+ bool IsSameClass(CBaseObject* obj) override;
- virtual bool Init(IEditor* ie, CBaseObject* prev, const QString& file);
- virtual void InitVariables();
- virtual void Done();
+ bool Init(IEditor* ie, CBaseObject* prev, const QString& file) override;
+ void InitVariables() override;
+ void Done() override;
void DrawExtraLightInfo (DisplayContext& disp);
@@ -102,29 +102,30 @@ public:
void SetEntityPropertyFloat(const char* name, float value);
void SetEntityPropertyString(const char* name, const QString& value);
- virtual int MouseCreateCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags);
- virtual void OnContextMenu(QMenu* menu);
+ int MouseCreateCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags) override;
+ void OnContextMenu(QMenu* menu) override;
- void SetName(const QString& name);
- void SetSelected(bool bSelect);
+ void SetName(const QString& name) override;
+ void SetSelected(bool bSelect) override;
- virtual void GetLocalBounds(AABB& box);
+ void GetLocalBounds(AABB& box) override;
- virtual bool HitTest(HitContext& hc);
- virtual bool HitHelperTest(HitContext& hc);
- virtual bool HitTestRect(HitContext& hc);
- void UpdateVisibility(bool bVisible);
- bool ConvertFromObject(CBaseObject* object);
+ bool HitTest(HitContext& hc) override;
+ bool HitHelperTest(HitContext& hc) override;
+ bool HitTestRect(HitContext& hc) override;
+ void UpdateVisibility(bool bVisible) override;
+ bool ConvertFromObject(CBaseObject* object) override;
- virtual void Serialize(CObjectArchive& ar);
- virtual void PostLoad(CObjectArchive& ar);
+ using CBaseObject::Serialize;
+ void Serialize(CObjectArchive& ar) override;
+ void PostLoad(CObjectArchive& ar) override;
- XmlNodeRef Export(const QString& levelPath, XmlNodeRef& xmlNode);
+ XmlNodeRef Export(const QString& levelPath, XmlNodeRef& xmlNode) override;
//////////////////////////////////////////////////////////////////////////
- void OnEvent(ObjectEvent event);
+ void OnEvent(ObjectEvent event) override;
- virtual void SetTransformDelegate(ITransformDelegate* pTransformDelegate) override;
+ void SetTransformDelegate(ITransformDelegate* pTransformDelegate) override;
// Set attach flags and target
enum EAttachmentType
@@ -139,15 +140,15 @@ public:
EAttachmentType GetAttachType() const { return m_attachmentType; }
QString GetAttachTarget() const { return m_attachmentTarget; }
- virtual void SetHelperScale(float scale);
- virtual float GetHelperScale();
+ void SetHelperScale(float scale) override;
+ float GetHelperScale() override;
- virtual void GatherUsedResources(CUsedResources& resources);
- virtual bool IsSimilarObject(CBaseObject* pObject);
+ void GatherUsedResources(CUsedResources& resources) override;
+ bool IsSimilarObject(CBaseObject* pObject) override;
- virtual bool HasMeasurementAxis() const { return false; }
+ bool HasMeasurementAxis() const override { return false; }
- virtual bool IsIsolated() const { return false; }
+ bool IsIsolated() const override { return false; }
//////////////////////////////////////////////////////////////////////////
// END CBaseObject
@@ -232,7 +233,7 @@ protected:
//////////////////////////////////////////////////////////////////////////
//! Must be called after cloning the object on clone of object.
//! This will make sure object references are cloned correctly.
- virtual void PostClone(CBaseObject* pFromObject, CObjectCloneContext& ctx);
+ void PostClone(CBaseObject* pFromObject, CObjectCloneContext& ctx) override;
//! Draw default object items.
void DrawProjectorPyramid(DisplayContext& dc, float dist);
@@ -264,7 +265,7 @@ public:
}
protected:
- void DeleteThis() { delete this; };
+ void DeleteThis() override { delete this; };
//////////////////////////////////////////////////////////////////////////
// Radius callbacks.
diff --git a/Code/Editor/Objects/GizmoManager.h b/Code/Editor/Objects/GizmoManager.h
index c3a71ad81b..efc3e99205 100644
--- a/Code/Editor/Objects/GizmoManager.h
+++ b/Code/Editor/Objects/GizmoManager.h
@@ -23,14 +23,14 @@ class CGizmoManager
: public IGizmoManager
{
public:
- void AddGizmo(CGizmo* gizmo);
- void RemoveGizmo(CGizmo* gizmo);
+ void AddGizmo(CGizmo* gizmo) override;
+ void RemoveGizmo(CGizmo* gizmo) override;
int GetGizmoCount() const override;
CGizmo* GetGizmoByIndex(int nIndex) const override;
- void Display(DisplayContext& dc);
- bool HitTest(HitContext& hc);
+ void Display(DisplayContext& dc) override;
+ bool HitTest(HitContext& hc) override;
void DeleteAllTransformManipulators();
diff --git a/Code/Editor/Objects/LineGizmo.h b/Code/Editor/Objects/LineGizmo.h
index af3b38b199..e50f044f3c 100644
--- a/Code/Editor/Objects/LineGizmo.h
+++ b/Code/Editor/Objects/LineGizmo.h
@@ -30,10 +30,10 @@ public:
//////////////////////////////////////////////////////////////////////////
// Ovverides from CGizmo
//////////////////////////////////////////////////////////////////////////
- virtual void SetName(const char* sName);
- virtual void GetWorldBounds(AABB& bbox);
- virtual void Display(DisplayContext& dc);
- virtual bool HitTest(HitContext& hc);
+ void SetName(const char* sName) override;
+ void GetWorldBounds(AABB& bbox) override;
+ void Display(DisplayContext& dc) override;
+ bool HitTest(HitContext& hc) override;
//////////////////////////////////////////////////////////////////////////
void SetObjects(CBaseObject* pObject1, CBaseObject* pObject2, const QString& boneName = "");
diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp
index e053d10fd1..06aa8866b3 100644
--- a/Code/Editor/Objects/ObjectManager.cpp
+++ b/Code/Editor/Objects/ObjectManager.cpp
@@ -52,6 +52,7 @@ public:
GUID guid;
public:
+ virtual ~CXMLObjectClassDesc() = default;
REFGUID ClassID() override
{
return guid;
diff --git a/Code/Editor/Objects/ObjectManager.h b/Code/Editor/Objects/ObjectManager.h
index de0a4ce849..4ffa5e9a07 100644
--- a/Code/Editor/Objects/ObjectManager.h
+++ b/Code/Editor/Objects/ObjectManager.h
@@ -103,142 +103,142 @@ public:
void RegisterObjectClasses();
- CBaseObject* NewObject(CObjectClassDesc* cls, CBaseObject* prev = 0, const QString& file = "", const char* newObjectName = nullptr);
- CBaseObject* NewObject(const QString& typeName, CBaseObject* prev = 0, const QString& file = "", const char* newEntityName = nullptr);
+ CBaseObject* NewObject(CObjectClassDesc* cls, CBaseObject* prev = 0, const QString& file = "", const char* newObjectName = nullptr) override;
+ CBaseObject* NewObject(const QString& typeName, CBaseObject* prev = 0, const QString& file = "", const char* newEntityName = nullptr) override;
- void DeleteObject(CBaseObject* obj);
- void DeleteSelection(CSelectionGroup* pSelection);
- void DeleteAllObjects();
- CBaseObject* CloneObject(CBaseObject* obj);
+ void DeleteObject(CBaseObject* obj) override;
+ void DeleteSelection(CSelectionGroup* pSelection) override;
+ void DeleteAllObjects() override;
+ CBaseObject* CloneObject(CBaseObject* obj) override;
- void BeginEditParams(CBaseObject* obj, int flags);
- void EndEditParams(int flags = 0);
+ void BeginEditParams(CBaseObject* obj, int flags) override;
+ void EndEditParams(int flags = 0) override;
// Hides all transform manipulators.
void HideTransformManipulators();
//! Get number of objects manager by ObjectManager (not contain sub objects of groups).
- int GetObjectCount() const;
+ int GetObjectCount() const override;
//! Get array of objects, managed by manager (not contain sub objects of groups).
//! @param layer if 0 get objects for all layers, or layer to get objects from.
- void GetObjects(CBaseObjectsArray& objects) const;
+ void GetObjects(CBaseObjectsArray& objects) const override;
//! Get array of objects that pass the filter.
//! @param filter The filter functor, return true if you want to get the certain obj, return false if want to skip it.
- void GetObjects(CBaseObjectsArray& objects, BaseObjectFilterFunctor const& filter) const;
+ void GetObjects(CBaseObjectsArray& objects, BaseObjectFilterFunctor const& filter) const override;
//! Update objects.
void Update();
//! Display objects on display context.
- void Display(DisplayContext& dc);
+ void Display(DisplayContext& dc) override;
//! Called when selecting without selection helpers - this is needed since
//! the visible object cache is normally not updated when not displaying helpers.
- void ForceUpdateVisibleObjectCache(DisplayContext& dc);
+ void ForceUpdateVisibleObjectCache(DisplayContext& dc) override;
//! Check intersection with objects.
//! Find intersection with nearest to ray origin object hit by ray.
//! If distance tollerance is specified certain relaxation applied on collision test.
//! @return true if hit any object, and fills hitInfo structure.
- bool HitTest(HitContext& hitInfo);
+ bool HitTest(HitContext& hitInfo) override;
//! Check intersection with an object.
//! @return true if hit, and fills hitInfo structure.
- bool HitTestObject(CBaseObject* obj, HitContext& hc);
+ bool HitTestObject(CBaseObject* obj, HitContext& hc) override;
//! Send event to all objects.
//! Will cause OnEvent handler to be called on all objects.
- void SendEvent(ObjectEvent event);
+ void SendEvent(ObjectEvent event) override;
//! Send event to all objects within given bounding box.
//! Will cause OnEvent handler to be called on objects within bounding box.
- void SendEvent(ObjectEvent event, const AABB& bounds);
+ void SendEvent(ObjectEvent event, const AABB& bounds) override;
//////////////////////////////////////////////////////////////////////////
//! Find object by ID.
- CBaseObject* FindObject(REFGUID guid) const;
+ CBaseObject* FindObject(REFGUID guid) const override;
//////////////////////////////////////////////////////////////////////////
//! Find object by name.
- CBaseObject* FindObject(const QString& sName) const;
+ CBaseObject* FindObject(const QString& sName) const override;
//////////////////////////////////////////////////////////////////////////
//! Find objects of given type.
void FindObjectsOfType(const QMetaObject* pClass, std::vector& result) override;
void FindObjectsOfType(ObjectType type, std::vector& result) override;
//////////////////////////////////////////////////////////////////////////
//! Find objects which intersect with a given AABB.
- virtual void FindObjectsInAABB(const AABB& aabb, std::vector& result) const;
+ void FindObjectsInAABB(const AABB& aabb, std::vector& result) const override;
//////////////////////////////////////////////////////////////////////////
// Operations on objects.
//////////////////////////////////////////////////////////////////////////
//! Makes object visible or invisible.
- void HideObject(CBaseObject* obj, bool hide);
+ void HideObject(CBaseObject* obj, bool hide) override;
//! Shows the last hidden object based on hidden ID
- void ShowLastHiddenObject();
+ void ShowLastHiddenObject() override;
//! Freeze object, making it unselectable.
- void FreezeObject(CBaseObject* obj, bool freeze);
+ void FreezeObject(CBaseObject* obj, bool freeze) override;
//! Unhide all hidden objects.
- void UnhideAll();
+ void UnhideAll() override;
//! Unfreeze all frozen objects.
- void UnfreezeAll();
+ void UnfreezeAll() override;
//////////////////////////////////////////////////////////////////////////
// Object Selection.
//////////////////////////////////////////////////////////////////////////
- bool SelectObject(CBaseObject* obj, bool bUseMask = true);
- void UnselectObject(CBaseObject* obj);
+ bool SelectObject(CBaseObject* obj, bool bUseMask = true) override;
+ void UnselectObject(CBaseObject* obj) override;
//! Select objects within specified distance from given position.
//! Return number of selected objects.
- int SelectObjects(const AABB& box, bool bUnselect = false);
+ int SelectObjects(const AABB& box, bool bUnselect = false) override;
- virtual void SelectEntities(std::set& s);
+ void SelectEntities(std::set& s) override;
- int MoveObjects(const AABB& box, const Vec3& offset, ImageRotationDegrees rotation, bool bIsCopy = false);
+ int MoveObjects(const AABB& box, const Vec3& offset, ImageRotationDegrees rotation, bool bIsCopy = false) override;
//! Selects/Unselects all objects within 2d rectangle in given viewport.
- void SelectObjectsInRect(CViewport* view, const QRect& rect, bool bSelect);
- void FindObjectsInRect(CViewport* view, const QRect& rect, std::vector& guids);
+ void SelectObjectsInRect(CViewport* view, const QRect& rect, bool bSelect) override;
+ void FindObjectsInRect(CViewport* view, const QRect& rect, std::vector& guids) override;
//! Clear default selection set.
//! @Return number of objects removed from selection.
- int ClearSelection();
+ int ClearSelection() override;
//! Deselect all current selected objects and selects object that were unselected.
//! @Return number of selected objects.
- int InvertSelection();
+ int InvertSelection() override;
//! Get current selection.
- CSelectionGroup* GetSelection() const { return m_currSelection; };
+ CSelectionGroup* GetSelection() const override { return m_currSelection; };
//! Get named selection.
- CSelectionGroup* GetSelection(const QString& name) const;
+ CSelectionGroup* GetSelection(const QString& name) const override;
// Get selection group names
- void GetNameSelectionStrings(QStringList& names);
+ void GetNameSelectionStrings(QStringList& names) override;
//! Change name of current selection group.
//! And store it in list.
- void NameSelection(const QString& name);
+ void NameSelection(const QString& name) override;
//! Set one of name selections as current selection.
- void SetSelection(const QString& name);
- void RemoveSelection(const QString& name);
+ void SetSelection(const QString& name) override;
+ void RemoveSelection(const QString& name) override;
bool IsObjectDeletionAllowed(CBaseObject* pObject);
//! Delete all objects in selection group.
- void DeleteSelection();
+ void DeleteSelection() override;
- uint32 ForceID() const{return m_ForceID; }
- void ForceID(uint32 FID){m_ForceID = FID; }
+ uint32 ForceID() const override{return m_ForceID; }
+ void ForceID(uint32 FID) override{m_ForceID = FID; }
//! Generates uniq name base on type name of object.
- QString GenerateUniqueObjectName(const QString& typeName);
+ QString GenerateUniqueObjectName(const QString& typeName) override;
//! Register object name in object manager, needed for generating uniq names.
- void RegisterObjectName(const QString& name);
+ void RegisterObjectName(const QString& name) override;
//! Decrease name number and remove if it was last in object manager, needed for generating uniq names.
void UpdateRegisterObjectName(const QString& name);
//! Enable/Disable generating of unique object names (Enabled by default).
//! Return previous value.
- bool EnableUniqObjectNames(bool bEnable);
+ bool EnableUniqObjectNames(bool bEnable) override;
//! Register XML template of runtime class.
void RegisterClassTemplate(const XmlNodeRef& templ);
@@ -249,25 +249,25 @@ public:
void RegisterCVars();
//! Find object class by name.
- CObjectClassDesc* FindClass(const QString& className);
- void GetClassCategories(QStringList& categories);
+ CObjectClassDesc* FindClass(const QString& className) override;
+ void GetClassCategories(QStringList& categories) override;
void GetClassCategoryToolClassNamePairs(std::vector< std::pair >& categoryToolClassNamePairs) override;
- void GetClassTypes(const QString& category, QStringList& types);
+ void GetClassTypes(const QString& category, QStringList& types) override;
//! Export objects to xml.
//! When onlyShared is true ony objects with shared flags exported, overwise only not shared object exported.
- void Export(const QString& levelPath, XmlNodeRef& rootNode, bool onlyShared);
- void ExportEntities(XmlNodeRef& rootNode);
+ void Export(const QString& levelPath, XmlNodeRef& rootNode, bool onlyShared) override;
+ void ExportEntities(XmlNodeRef& rootNode) override;
//! Serialize Objects in manager to specified XML Node.
//! @param flags Can be one of SerializeFlags.
- void Serialize(XmlNodeRef& rootNode, bool bLoading, int flags = SERIALIZE_ALL);
+ void Serialize(XmlNodeRef& rootNode, bool bLoading, int flags = SERIALIZE_ALL) override;
- void SerializeNameSelection(XmlNodeRef& rootNode, bool bLoading);
+ void SerializeNameSelection(XmlNodeRef& rootNode, bool bLoading) override;
//! Load objects from object archive.
//! @param bSelect if set newly loaded object will be selected.
- void LoadObjects(CObjectArchive& ar, bool bSelect);
+ void LoadObjects(CObjectArchive& ar, bool bSelect) override;
//! Delete from Object manager all objects without SHARED flag.
void DeleteNotSharedObjects();
@@ -276,57 +276,57 @@ public:
bool AddObject(CBaseObject* obj);
void RemoveObject(CBaseObject* obj);
- void ChangeObjectId(REFGUID oldId, REFGUID newId);
- bool IsDuplicateObjectName(const QString& newName) const
+ void ChangeObjectId(REFGUID oldId, REFGUID newId) override;
+ bool IsDuplicateObjectName(const QString& newName) const override
{
return FindObject(newName) ? true : false;
}
- void ShowDuplicationMsgWarning(CBaseObject* obj, const QString& newName, bool bShowMsgBox) const;
- void ChangeObjectName(CBaseObject* obj, const QString& newName);
+ void ShowDuplicationMsgWarning(CBaseObject* obj, const QString& newName, bool bShowMsgBox) const override;
+ void ChangeObjectName(CBaseObject* obj, const QString& newName) override;
//! Convert object of one type to object of another type.
//! Original object is deleted.
- bool ConvertToType(CBaseObject* pObject, const QString& typeName);
+ bool ConvertToType(CBaseObject* pObject, const QString& typeName) override;
//! Set new selection callback.
//! @return previous selection callback.
- IObjectSelectCallback* SetSelectCallback(IObjectSelectCallback* callback);
+ IObjectSelectCallback* SetSelectCallback(IObjectSelectCallback* callback) override;
// Enables/Disables creating of game objects.
- void SetCreateGameObject(bool enable) { m_createGameObjects = enable; };
+ void SetCreateGameObject(bool enable) override { m_createGameObjects = enable; };
//! Return true if objects loaded from xml should immidiatly create game objects associated with them.
- bool IsCreateGameObjects() const { return m_createGameObjects; };
+ bool IsCreateGameObjects() const override { return m_createGameObjects; };
//////////////////////////////////////////////////////////////////////////
//! Get access to gizmo manager.
- IGizmoManager* GetGizmoManager();
+ IGizmoManager* GetGizmoManager() override;
//////////////////////////////////////////////////////////////////////////
//! Invalidate visibily settings of objects.
- void InvalidateVisibleList();
+ void InvalidateVisibleList() override;
//////////////////////////////////////////////////////////////////////////
// ObjectManager notification Callbacks.
//////////////////////////////////////////////////////////////////////////
- void AddObjectEventListener(EventListener* listener);
- void RemoveObjectEventListener(EventListener* listener);
+ void AddObjectEventListener(EventListener* listener) override;
+ void RemoveObjectEventListener(EventListener* listener) override;
//////////////////////////////////////////////////////////////////////////
// Used to indicate starting and ending of objects loading.
//////////////////////////////////////////////////////////////////////////
- void StartObjectsLoading(int numObjects);
- void EndObjectsLoading();
+ void StartObjectsLoading(int numObjects) override;
+ void EndObjectsLoading() override;
//////////////////////////////////////////////////////////////////////////
// Gathers all resources used by all objects.
- void GatherUsedResources(CUsedResources& resources);
+ void GatherUsedResources(CUsedResources& resources) override;
- virtual bool IsLightClass(CBaseObject* pObject);
+ bool IsLightClass(CBaseObject* pObject) override;
- virtual void FindAndRenameProperty2(const char* property2Name, const QString& oldValue, const QString& newValue);
- virtual void FindAndRenameProperty2If(const char* property2Name, const QString& oldValue, const QString& newValue, const char* otherProperty2Name, const QString& otherValue);
+ virtual void FindAndRenameProperty2(const char* property2Name, const QString& oldValue, const QString& newValue) override;
+ virtual void FindAndRenameProperty2If(const char* property2Name, const QString& oldValue, const QString& newValue, const char* otherProperty2Name, const QString& otherValue) override;
- bool IsReloading() const { return m_bInReloading; }
+ bool IsReloading() const override { return m_bInReloading; }
void SetSkipUpdate(bool bSkipUpdate) override { m_bSkipObjectUpdate = bSkipUpdate; }
void SetExportingLevel(bool bExporting) override { m_bLevelExporting = bExporting; }
@@ -341,7 +341,7 @@ private:
@param objectNode Xml node to serialize object info from.
@param pUndoObject Pointer to deleted object for undo.
*/
- CBaseObject* NewObject(CObjectArchive& archive, CBaseObject* pUndoObject, bool bMakeNewId);
+ CBaseObject* NewObject(CObjectArchive& archive, CBaseObject* pUndoObject, bool bMakeNewId) override;
//! Update visibility of all objects.
void UpdateVisibilityList();
diff --git a/Code/Editor/Platform/Mac/EditorEntitlements.plist b/Code/Editor/Platform/Mac/EditorEntitlements.plist
new file mode 100644
index 0000000000..cefa2bf93b
--- /dev/null
+++ b/Code/Editor/Platform/Mac/EditorEntitlements.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.security.cs.allow-dyld-environment-variables
+
+ com.apple.security.cs.disable-library-validation
+
+
+
diff --git a/Code/Editor/Platform/Mac/editor_mac.cmake b/Code/Editor/Platform/Mac/editor_mac.cmake
index fdccfafb46..eed955f2e4 100644
--- a/Code/Editor/Platform/Mac/editor_mac.cmake
+++ b/Code/Editor/Platform/Mac/editor_mac.cmake
@@ -12,28 +12,5 @@ set_target_properties(Editor PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_LIST_DIR}/gui_info.plist
RESOURCE ${CMAKE_CURRENT_LIST_DIR}/Images.xcassets
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME EditorAppIcon
+ ENTITLEMENT_FILE_PATH ${CMAKE_CURRENT_LIST_DIR}/EditorEntitlements.plist
)
-
-# We cannot use ly_add_target here because we're already including this file from inside ly_add_target
-# So we need to setup target, dependencies and install logic manually.
-add_executable(EditorDummy Platform/Mac/main_dummy.cpp)
-add_executable(AZ::EditorDummy ALIAS EditorDummy)
-
-ly_target_link_libraries(EditorDummy
- PRIVATE
- AZ::AzCore
- AZ::AzFramework)
-
-ly_add_dependencies(Editor EditorDummy)
-
-# Store the aliased target into a DIRECTORY property
-set_property(DIRECTORY APPEND PROPERTY LY_DIRECTORY_TARGETS AZ::EditorDummy)
-
-# Store the directory path in a GLOBAL property so that it can be accessed
-# in the layout install logic. Skip if the directory has already been added
-get_property(ly_all_target_directories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES)
-if(NOT CMAKE_CURRENT_SOURCE_DIR IN_LIST ly_all_target_directories)
- set_property(GLOBAL APPEND PROPERTY LY_ALL_TARGET_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR})
-endif()
-
-ly_install_add_install_path_setreg(Editor)
\ No newline at end of file
diff --git a/Code/Editor/Platform/Mac/gui_info.plist b/Code/Editor/Platform/Mac/gui_info.plist
index cc87cbbb47..5b5f94e977 100644
--- a/Code/Editor/Platform/Mac/gui_info.plist
+++ b/Code/Editor/Platform/Mac/gui_info.plist
@@ -3,7 +3,7 @@
CFBundleExecutable
- EditorDummy
+ Editor
CFBundleIdentifier
org.O3DE.Editor
CFBundlePackageType
diff --git a/Code/Editor/Platform/Mac/main_dummy.cpp b/Code/Editor/Platform/Mac/main_dummy.cpp
deleted file mode 100644
index 348a32ab47..0000000000
--- a/Code/Editor/Platform/Mac/main_dummy.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-int main(int argc, char* argv[])
-{
- // Create a ComponentApplication to initialize the AZ::SystemAllocator and initialize the SettingsRegistry
- AZ::ComponentApplication::Descriptor desc;
- AZ::ComponentApplication application;
- application.Create(desc);
-
- AZStd::vector envVars;
-
- const char* homePath = std::getenv("HOME");
- envVars.push_back(AZStd::string::format("HOME=%s", homePath));
-
- if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
- {
- const char* dyldLibPathOrig = std::getenv("DYLD_LIBRARY_PATH");
- AZStd::string dyldSearchPath = AZStd::string::format("DYLD_LIBRARY_PATH=%s", dyldLibPathOrig);
- if (AZ::IO::FixedMaxPath projectModulePath;
- settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
- {
- dyldSearchPath.append(":");
- dyldSearchPath.append(projectModulePath.c_str());
- }
-
- if (AZ::IO::FixedMaxPath installedBinariesFolder;
- settingsRegistry->Get(installedBinariesFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
- {
- if (AZ::IO::FixedMaxPath engineRootFolder;
- settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
- {
- installedBinariesFolder = engineRootFolder / installedBinariesFolder;
- dyldSearchPath.append(":");
- dyldSearchPath.append(installedBinariesFolder.c_str());
- }
- }
- envVars.push_back(dyldSearchPath);
- }
-
- AZStd::string commandArgs;
- for (int i = 1; i < argc; i++)
- {
- commandArgs.append(argv[i]);
- commandArgs.append(" ");
- }
-
- AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
- AZ::IO::Path processPath{ AZ::IO::PathView(AZ::Utils::GetExecutableDirectory()) };
- processPath /= "Editor";
- processLaunchInfo.m_processExecutableString = AZStd::move(processPath.Native());
- processLaunchInfo.m_commandlineParameters = commandArgs;
- processLaunchInfo.m_environmentVariables = &envVars;
- processLaunchInfo.m_showWindow = true;
-
- AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
-
- application.Destroy();
-
- return 0;
-}
-
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h
index 23151eb05c..bb19f4d77e 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h
@@ -86,7 +86,7 @@ public:
// Always returns false as Component entity highlighting (accenting) is taken care of elsewhere
bool IsHighlighted() { return false; }
// Component entity highlighting (accenting) is taken care of elsewhere
- void DrawHighlight(DisplayContext& /*dc*/) {};
+ void DrawHighlight(DisplayContext& /*dc*/) override {};
// Don't auto-clone children. Cloning happens in groups with reference fixups,
// and individually selected objercts should be cloned as individuals.
@@ -164,7 +164,7 @@ protected:
float GetRadius();
- void DeleteThis() { delete this; };
+ void DeleteThis() override { delete this; };
bool IsNonLayerAncestorSelected() const;
bool IsLayer() const;
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
index f2764681b2..617c5cb2c8 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
@@ -182,7 +182,7 @@ private:
//////////////////////////////////////////////////////////////////////////
// AzToolsFramework::EditorContextMenu::Bus::Handler overrides
void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override;
- int GetMenuPosition() const;
+ int GetMenuPosition() const override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/FavoriteComponentList.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/FavoriteComponentList.h
index 5f704237ab..2bd2d83e04 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/FavoriteComponentList.h
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/ComponentPalette/FavoriteComponentList.h
@@ -102,7 +102,7 @@ protected:
void AddFavorites(const AZStd::vector& classDataContainer) override;
//////////////////////////////////////////////////////////////////////////
- void rowsInserted(const QModelIndex& parent, int start, int end);
+ void rowsInserted(const QModelIndex& parent, int start, int end) override;
// Context menu handlers
void ShowContextMenu(const QPoint&);
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.hxx b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.hxx
index 346a5e938a..8acb2f1a72 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.hxx
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerListModel.hxx
@@ -255,7 +255,7 @@ protected:
bool DropMimeDataAssets(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
bool CanDropMimeDataAssets(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const;
- QMap itemData(const QModelIndex &index) const;
+ QMap itemData(const QModelIndex &index) const override;
QVariant dataForAll(const QModelIndex& index, int role) const;
QVariant dataForName(const QModelIndex& index, int role) const;
QVariant dataForVisibility(const QModelIndex& index, int role) const;
diff --git a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
index 2aff57cfb1..cd9f2e79c7 100644
--- a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
+++ b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
@@ -51,4 +51,5 @@ ly_add_target(
AZ::AzCore
AZ::AzToolsFramework
AZ::AzQtComponents
+ Legacy::EditorCore
)
diff --git a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp
index 10c43c3d1b..dd9ccaa832 100644
--- a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp
+++ b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.cpp
@@ -6,6 +6,7 @@
*
*/
+#include
#include "CryFile.h"
#include "PerforceSourceControl.h"
#include "PasswordDlg.h"
diff --git a/Code/Editor/PreferencesStdPages.h b/Code/Editor/PreferencesStdPages.h
index f4a6e0b783..8a182bde55 100644
--- a/Code/Editor/PreferencesStdPages.h
+++ b/Code/Editor/PreferencesStdPages.h
@@ -28,16 +28,16 @@ public:
//////////////////////////////////////////////////////////////////////////
// IUnkown implementation.
- virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObj);
- virtual ULONG STDMETHODCALLTYPE AddRef();
- virtual ULONG STDMETHODCALLTYPE Release();
+ HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObj) override;
+ ULONG STDMETHODCALLTYPE AddRef() override;
+ ULONG STDMETHODCALLTYPE Release() override;
//////////////////////////////////////////////////////////////////////////
- virtual REFGUID ClassID();
+ REFGUID ClassID() override;
//////////////////////////////////////////////////////////////////////////
- virtual int GetPagesCount();
- virtual IPreferencesPage* CreateEditorPreferencesPage(int index) override;
+ int GetPagesCount() override;
+ IPreferencesPage* CreateEditorPreferencesPage(int index) override;
};
#endif // CRYINCLUDE_EDITOR_PREFERENCESSTDPAGES_H
diff --git a/Code/Editor/PythonEditorEventsBus.h b/Code/Editor/PythonEditorEventsBus.h
index 5107a1c9cc..ffc357e64d 100644
--- a/Code/Editor/PythonEditorEventsBus.h
+++ b/Code/Editor/PythonEditorEventsBus.h
@@ -8,6 +8,7 @@
*/
#pragma once
+#include
#include
namespace AzToolsFramework
@@ -138,7 +139,7 @@ namespace AzToolsFramework
/*
* Finds a pak file name for a given file.
*/
- virtual const char* GetPakFromFile(const char* filename) = 0;
+ virtual AZ::IO::Path GetPakFromFile(const char* filename) = 0;
/*
* Prints the message to the editor console window.
diff --git a/Code/Editor/PythonEditorFuncs.cpp b/Code/Editor/PythonEditorFuncs.cpp
index 200fd28f87..455cdfa17d 100644
--- a/Code/Editor/PythonEditorFuncs.cpp
+++ b/Code/Editor/PythonEditorFuncs.cpp
@@ -625,7 +625,7 @@ namespace
}
//////////////////////////////////////////////////////////////////////////
- const char* PyGetPakFromFile(const char* filename)
+ AZ::IO::Path PyGetPakFromFile(const char* filename)
{
auto pIPak = GetIEditor()->GetSystem()->GetIPak();
AZ::IO::HandleType fileHandle = pIPak->FOpen(filename, "rb");
@@ -633,8 +633,9 @@ namespace
{
throw std::logic_error("Invalid file name.");
}
- const char* pArchPath = pIPak->GetFileArchivePath(fileHandle);
+ AZ::IO::Path pArchPath = pIPak->GetFileArchivePath(fileHandle);
pIPak->FClose(fileHandle);
+
return pArchPath;
}
@@ -1040,7 +1041,7 @@ namespace AzToolsFramework
return PySetAxisConstraint(pConstrain);
}
- const char* PythonEditorComponent::GetPakFromFile(const char* filename)
+ AZ::IO::Path PythonEditorComponent::GetPakFromFile(const char* filename)
{
return PyGetPakFromFile(filename);
}
@@ -1114,7 +1115,7 @@ namespace AzToolsFramework
addLegacyGeneral(behaviorContext->Method("get_axis_constraint", PyGetAxisConstraint, nullptr, "Gets axis."));
addLegacyGeneral(behaviorContext->Method("set_axis_constraint", PySetAxisConstraint, nullptr, "Sets axis."));
- addLegacyGeneral(behaviorContext->Method("get_pak_from_file", PyGetPakFromFile, nullptr, "Finds a pak file name for a given file."));
+ addLegacyGeneral(behaviorContext->Method("get_pak_from_file", [](const char* filename) -> AZStd::string { return PyGetPakFromFile(filename).Native(); }, nullptr, "Finds a pak file name for a given file."));
addLegacyGeneral(behaviorContext->Method("log", PyLog, nullptr, "Prints the message to the editor console window."));
diff --git a/Code/Editor/PythonEditorFuncs.h b/Code/Editor/PythonEditorFuncs.h
index 97ad8829ba..ef0c1327fa 100644
--- a/Code/Editor/PythonEditorFuncs.h
+++ b/Code/Editor/PythonEditorFuncs.h
@@ -91,7 +91,7 @@ namespace AzToolsFramework
void SetAxisConstraint(AZStd::string_view pConstrain) override;
- const char* GetPakFromFile(const char* filename) override;
+ AZ::IO::Path GetPakFromFile(const char* filename) override;
void Log(const char* pMessage) override;
diff --git a/Code/Editor/QtViewPane.h b/Code/Editor/QtViewPane.h
index 09fc215833..194dd8919a 100644
--- a/Code/Editor/QtViewPane.h
+++ b/Code/Editor/QtViewPane.h
@@ -123,18 +123,18 @@ public:
{
}
- virtual ESystemClassID SystemClassID() { return m_classId; };
+ ESystemClassID SystemClassID() override { return m_classId; };
static const GUID& GetClassID()
{
return TWidget::GetClassID();
}
- virtual const GUID& ClassID()
+ const GUID& ClassID() override
{
return GetClassID();
}
- virtual QString ClassName() { return m_name; };
- virtual QString Category() { return m_category; };
+ QString ClassName() override { return m_name; };
+ QString Category() override { return m_category; };
QObject* CreateQObject() const override { return new TWidget(); };
QString GetPaneTitle() override { return m_name; };
diff --git a/Code/Editor/SelectSequenceDialog.h b/Code/Editor/SelectSequenceDialog.h
index 5531949c1a..960da7ebe3 100644
--- a/Code/Editor/SelectSequenceDialog.h
+++ b/Code/Editor/SelectSequenceDialog.h
@@ -30,7 +30,7 @@ protected:
void OnInitDialog() override;
// Derived Dialogs should override this
- virtual void GetItems(std::vector& outItems);
+ void GetItems(std::vector& outItems) override;
};
#endif // CRYINCLUDE_EDITOR_SELECTSEQUENCEDIALOG_H
diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp
index 80d248e1bf..05a6960695 100644
--- a/Code/Editor/Settings.cpp
+++ b/Code/Editor/Settings.cpp
@@ -171,7 +171,6 @@ SEditorSettings::SEditorSettings()
bBackupOnSave = true;
backupOnSaveMaxCount = 3;
bApplyConfigSpecInEditor = true;
- useLowercasePaths = 0;
showErrorDialogOnLoad = 1;
consoleBackgroundColorTheme = AzToolsFramework::ConsoleColorTheme::Dark;
@@ -887,6 +886,7 @@ void SEditorSettings::Load()
//////////////////////////////////////////////////////////////////////////
AZ_CVAR(bool, ed_previewGameInFullscreen_once, false, nullptr, AZ::ConsoleFunctorFlags::IsInvisible, "Preview the game (Ctrl+G, \"Play Game\", etc.) in fullscreen once");
+AZ_CVAR(bool, ed_lowercasepaths, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Convert CCryFile paths to lowercase on Open");
void SEditorSettings::PostInitApply()
{
@@ -898,7 +898,6 @@ void SEditorSettings::PostInitApply()
// Create CVars.
REGISTER_CVAR2("ed_highlightGeometry", &viewports.bHighlightMouseOverGeometry, viewports.bHighlightMouseOverGeometry, 0, "Highlight geometry when mouse over it");
REGISTER_CVAR2("ed_showFrozenHelpers", &viewports.nShowFrozenHelpers, viewports.nShowFrozenHelpers, 0, "Show helpers of frozen objects");
- REGISTER_CVAR2("ed_lowercasepaths", &useLowercasePaths, useLowercasePaths, 0, "generate paths in lowercase");
gEnv->pConsole->RegisterInt("fe_fbx_savetempfile", 0, 0, "When importing an FBX file into Facial Editor, this will save out a conversion FSQ to the Animations/temp folder for trouble shooting");
REGISTER_CVAR2_CB("ed_toolbarIconSize", &gui.nToolbarIconSize, gui.nToolbarIconSize, VF_NULL, "Override size of the toolbar icons 0-default, 16,32,...", ToolbarIconSizeChanged);
diff --git a/Code/Editor/Settings.h b/Code/Editor/Settings.h
index a408822129..8bf22b43e5 100644
--- a/Code/Editor/Settings.h
+++ b/Code/Editor/Settings.h
@@ -340,8 +340,6 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
//! how many save backups to keep
int backupOnSaveMaxCount;
- int useLowercasePaths;
-
//////////////////////////////////////////////////////////////////////////
// Autobackup.
//////////////////////////////////////////////////////////////////////////
diff --git a/Code/Editor/ToolbarCustomizationDialog.h b/Code/Editor/ToolbarCustomizationDialog.h
index 7063c2b792..0e64bfbb5b 100644
--- a/Code/Editor/ToolbarCustomizationDialog.h
+++ b/Code/Editor/ToolbarCustomizationDialog.h
@@ -39,7 +39,7 @@ public:
protected:
void dragMoveEvent(QDragMoveEvent* ev) override;
void dragEnterEvent(QDragEnterEvent* ev) override;
- void dropEvent(QDropEvent* ev);
+ void dropEvent(QDropEvent* ev) override;
private:
void OnTabChanged(int index);
diff --git a/Code/Editor/TopRendererWnd.h b/Code/Editor/TopRendererWnd.h
index 3a5c1026bc..c5bc7a31f2 100644
--- a/Code/Editor/TopRendererWnd.h
+++ b/Code/Editor/TopRendererWnd.h
@@ -35,11 +35,11 @@ public:
/** Get type of this viewport.
*/
- virtual EViewportType GetType() const { return ET_ViewportMap; }
- virtual void SetType(EViewportType type);
+ EViewportType GetType() const override { return ET_ViewportMap; }
+ void SetType(EViewportType type) override;
- virtual void ResetContent();
- virtual void UpdateContent(int flags);
+ void ResetContent() override;
+ void UpdateContent(int flags) override;
//! Map viewport position to world space position.
virtual Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override;
@@ -52,7 +52,7 @@ public:
protected:
// Draw everything.
- virtual void Draw(DisplayContext& dc);
+ void Draw(DisplayContext& dc) override;
private:
bool m_bContentsUpdated;
diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.h b/Code/Editor/TrackView/SequenceBatchRenderDialog.h
index 5d8934f783..9be10c22af 100644
--- a/Code/Editor/TrackView/SequenceBatchRenderDialog.h
+++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.h
@@ -187,7 +187,7 @@ protected:
int m_customFPS;
void InitializeContext();
- virtual void OnMovieEvent(IMovieListener::EMovieEvent event, IAnimSequence* pSequence);
+ void OnMovieEvent(IMovieListener::EMovieEvent event, IAnimSequence* pSequence) override;
void CaptureItemStart();
diff --git a/Code/Editor/TrackView/TrackViewCurveEditor.h b/Code/Editor/TrackView/TrackViewCurveEditor.h
index b2e019899b..1af55a9e0c 100644
--- a/Code/Editor/TrackView/TrackViewCurveEditor.h
+++ b/Code/Editor/TrackView/TrackViewCurveEditor.h
@@ -50,8 +50,8 @@ public:
void SetPlayCallback(const std::function& callback);
// IAnimationContextListener
- virtual void OnSequenceChanged(CTrackViewSequence* pNewSequence);
- virtual void OnTimeChanged(float newTime);
+ void OnSequenceChanged(CTrackViewSequence* pNewSequence) override;
+ void OnTimeChanged(float newTime) override;
protected:
void showEvent(QShowEvent* event) override;
@@ -65,7 +65,7 @@ private:
void OnSplineTimeMarkerChange();
// IEditorNotifyListener
- virtual void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
+ void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
//ITrackViewSequenceListener
void OnKeysChanged(CTrackViewSequence* pSequence) override;
@@ -109,8 +109,8 @@ public:
float GetFPS() const { return m_widget->GetFPS(); }
void SetTickDisplayMode(ETVTickMode mode) { m_widget->SetTickDisplayMode(mode); }
- virtual void OnSequenceChanged(CTrackViewSequence* pNewSequence) { m_widget->OnSequenceChanged(pNewSequence); }
- virtual void OnTimeChanged(float newTime) { m_widget->OnTimeChanged(newTime); }
+ void OnSequenceChanged(CTrackViewSequence* pNewSequence) override { m_widget->OnSequenceChanged(pNewSequence); }
+ void OnTimeChanged(float newTime) override { m_widget->OnTimeChanged(newTime); }
// ITrackViewSequenceListener delegation to m_widget
void OnKeysChanged(CTrackViewSequence* pSequence) override { m_widget->OnKeysChanged(pSequence); }
diff --git a/Code/Editor/TrackView/TrackViewDialog.h b/Code/Editor/TrackView/TrackViewDialog.h
index f6c1126713..c66f31e1f7 100644
--- a/Code/Editor/TrackView/TrackViewDialog.h
+++ b/Code/Editor/TrackView/TrackViewDialog.h
@@ -69,10 +69,10 @@ public:
void UpdateSequenceLockStatus();
// IAnimationContextListener
- virtual void OnSequenceChanged(CTrackViewSequence* pNewSequence) override;
+ void OnSequenceChanged(CTrackViewSequence* pNewSequence) override;
// ITrackViewSequenceListener
- virtual void OnSequenceSettingsChanged(CTrackViewSequence* pSequence) override;
+ void OnSequenceSettingsChanged(CTrackViewSequence* pSequence) override;
void UpdateDopeSheetTime(CTrackViewSequence* pSequence);
@@ -197,8 +197,8 @@ private:
bool processRawInput(MSG* pMsg);
#endif
- virtual void OnNodeSelectionChanged(CTrackViewSequence* pSequence) override;
- virtual void OnNodeRenamed(CTrackViewNode* pNode, const char* pOldName) override;
+ void OnNodeSelectionChanged(CTrackViewSequence* pSequence) override;
+ void OnNodeRenamed(CTrackViewNode* pNode, const char* pOldName) override;
void OnSequenceAdded(CTrackViewSequence* pSequence) override;
void OnSequenceRemoved(CTrackViewSequence* pSequence) override;
@@ -209,8 +209,8 @@ private:
void AddDialogListeners();
void RemoveDialogListeners();
- virtual void BeginUndoTransaction();
- virtual void EndUndoTransaction();
+ void BeginUndoTransaction() override;
+ void EndUndoTransaction() override;
void SaveCurrentSequenceToFBX();
void SaveSequenceTimingToXML();
diff --git a/Code/Editor/TrackView/TrackViewNode.h b/Code/Editor/TrackView/TrackViewNode.h
index 59df06750b..80ca7b9d49 100644
--- a/Code/Editor/TrackView/TrackViewNode.h
+++ b/Code/Editor/TrackView/TrackViewNode.h
@@ -117,13 +117,14 @@ class CTrackViewKeyBundle
public:
CTrackViewKeyBundle()
: m_bAllOfSameType(true) {}
+ virtual ~CTrackViewKeyBundle() = default;
- virtual bool AreAllKeysOfSameType() const override { return m_bAllOfSameType; }
+ bool AreAllKeysOfSameType() const override { return m_bAllOfSameType; }
- virtual unsigned int GetKeyCount() const override { return static_cast(m_keys.size()); }
- virtual CTrackViewKeyHandle GetKey(unsigned int index) override { return m_keys[index]; }
+ unsigned int GetKeyCount() const override { return static_cast(m_keys.size()); }
+ CTrackViewKeyHandle GetKey(unsigned int index) override { return m_keys[index]; }
- virtual void SelectKeys(const bool bSelected) override;
+ void SelectKeys(const bool bSelected) override;
CTrackViewKeyHandle GetSingleSelectedKey();
diff --git a/Code/Editor/TrackView/TrackViewSequence.h b/Code/Editor/TrackView/TrackViewSequence.h
index 69858adf8f..a392ad00f9 100644
--- a/Code/Editor/TrackView/TrackViewSequence.h
+++ b/Code/Editor/TrackView/TrackViewSequence.h
@@ -100,16 +100,16 @@ public:
void Load() override;
// ITrackViewNode
- virtual ETrackViewNodeType GetNodeType() const override { return eTVNT_Sequence; }
+ ETrackViewNodeType GetNodeType() const override { return eTVNT_Sequence; }
- virtual AZStd::string GetName() const override { return m_pAnimSequence->GetName(); }
- virtual bool SetName(const char* pName) override;
- virtual bool CanBeRenamed() const override { return true; }
+ AZStd::string GetName() const override { return m_pAnimSequence->GetName(); }
+ bool SetName(const char* pName) override;
+ bool CanBeRenamed() const override { return true; }
// Binding/Unbinding
- virtual void BindToEditorObjects() override;
- virtual void UnBindFromEditorObjects() override;
- virtual bool IsBoundToEditorObjects() const override;
+ void BindToEditorObjects() override;
+ void UnBindFromEditorObjects() override;
+ bool IsBoundToEditorObjects() const override;
// Time range
void SetTimeRange(Range timeRange);
@@ -136,10 +136,10 @@ public:
uint32 GetCryMovieId() const { return m_pAnimSequence->GetId(); }
// Rendering
- virtual void Render(const SAnimContext& animContext) override;
+ void Render(const SAnimContext& animContext) override;
// Playback control
- virtual void Animate(const SAnimContext& animContext) override;
+ void Animate(const SAnimContext& animContext) override;
void Resume() { m_pAnimSequence->Resume(); }
void Pause() { m_pAnimSequence->Pause(); }
void StillUpdate() { m_pAnimSequence->StillUpdate(); }
@@ -162,7 +162,7 @@ public:
void TimeChanged(float newTime) { m_pAnimSequence->TimeChanged(newTime); }
// Check if it's a group node
- virtual bool IsGroupNode() const override { return true; }
+ bool IsGroupNode() const override { return true; }
// Track Events (TODO: Undo?)
int GetTrackEventsCount() const { return m_pAnimSequence->GetTrackEventsCount(); }
@@ -195,7 +195,7 @@ public:
bool IsActiveSequence() const;
// The root sequence node is always an active director
- virtual bool IsActiveDirector() const override { return true; }
+ bool IsActiveDirector() const override { return true; }
// Copy keys to clipboard (in XML form)
void CopyKeysToClipboard(const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks);
@@ -306,15 +306,15 @@ private:
// Called when an animation updates needs to be schedules
void ForceAnimation();
- virtual void CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks) override;
+ void CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks) override;
std::deque GetMatchingTracks(CTrackViewAnimNode* pAnimNode, XmlNodeRef trackNode);
void GetMatchedPasteLocationsRec(std::vector& locations, CTrackViewNode* pCurrentNode, XmlNodeRef clipboardNode);
- virtual void BeginUndoTransaction();
- virtual void EndUndoTransaction();
- virtual void BeginRestoreTransaction();
- virtual void EndRestoreTransaction();
+ void BeginUndoTransaction() override;
+ void EndUndoTransaction() override;
+ void BeginRestoreTransaction() override;
+ void EndRestoreTransaction() override;
// For record mode on AZ::Entities - connect (or disconnect) to buses for notification of property changes
void ConnectToBusesForRecording(const AZ::EntityId& entityIdForBus, bool enableConnection);
diff --git a/Code/Editor/TrackView/TrackViewSequenceManager.h b/Code/Editor/TrackView/TrackViewSequenceManager.h
index 21c10f009a..1474323dc6 100644
--- a/Code/Editor/TrackView/TrackViewSequenceManager.h
+++ b/Code/Editor/TrackView/TrackViewSequenceManager.h
@@ -27,7 +27,7 @@ public:
CTrackViewSequenceManager();
~CTrackViewSequenceManager();
- virtual void OnEditorNotifyEvent(EEditorNotifyEvent event);
+ void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
unsigned int GetCount() const { return static_cast(m_sequences.size()); }
@@ -65,7 +65,7 @@ private:
void OnSequenceAdded(CTrackViewSequence* pSequence);
void OnSequenceRemoved(CTrackViewSequence* pSequence);
- virtual void OnDataBaseItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event);
+ void OnDataBaseItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event) override;
// AZ::EntitySystemBus
void OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) override;
diff --git a/Code/Editor/TrackView/TrackViewSplineCtrl.h b/Code/Editor/TrackView/TrackViewSplineCtrl.h
index 2f4c790627..7cf12fb750 100644
--- a/Code/Editor/TrackView/TrackViewSplineCtrl.h
+++ b/Code/Editor/TrackView/TrackViewSplineCtrl.h
@@ -28,7 +28,7 @@ public:
CTrackViewSplineCtrl(QWidget* parent);
virtual ~CTrackViewSplineCtrl();
- virtual void ClearSelection();
+ void ClearSelection() override;
void AddSpline(ISplineInterpolator* pSpline, CTrackViewTrack* pTrack, const QColor& color);
void AddSpline(ISplineInterpolator * pSpline, CTrackViewTrack * pTrack, QColor anColorArray[4]);
@@ -53,12 +53,12 @@ protected:
void wheelEvent(QWheelEvent* event) override;
private:
- virtual void SelectKey(ISplineInterpolator* pSpline, int nKey, int nDimension, bool bSelect) override;
- virtual void SelectRectangle(const QRect& rc, bool bSelect) override;
+ void SelectKey(ISplineInterpolator* pSpline, int nKey, int nDimension, bool bSelect) override;
+ void SelectRectangle(const QRect& rc, bool bSelect) override;
std::vector m_tracks;
- virtual bool GetTangentHandlePts(QPoint& inTangentPt, QPoint& pt, QPoint& outTangentPt,
+ bool GetTangentHandlePts(QPoint& inTangentPt, QPoint& pt, QPoint& outTangentPt,
int nSpline, int nKey, int nDimension) override;
void ComputeIncomingTangentAndEaseTo(float& ds, float& easeTo, QPoint inTangentPt,
int nSpline, int nKey, int nDimension);
@@ -67,7 +67,7 @@ private:
void AdjustTCB(float d_tension, float d_continuity, float d_bias);
void MoveSelectedTangentHandleTo(const QPoint& point);
- virtual ISplineCtrlUndo* CreateSplineCtrlUndoObject(std::vector& splineContainer);
+ ISplineCtrlUndo* CreateSplineCtrlUndoObject(std::vector& splineContainer) override;
bool m_bKeysFreeze;
bool m_bTangentsFreeze;
diff --git a/Code/Editor/Util/ColumnGroupTreeView.h b/Code/Editor/Util/ColumnGroupTreeView.h
index 3c7dea91c3..eda5f8e9c9 100644
--- a/Code/Editor/Util/ColumnGroupTreeView.h
+++ b/Code/Editor/Util/ColumnGroupTreeView.h
@@ -44,7 +44,7 @@ public slots:
QVector Groups() const;
protected:
- void paintEvent(QPaintEvent* event)
+ void paintEvent(QPaintEvent* event) override
{
if (model() && model()->rowCount() > 0)
{
diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp
index 610a9c6e16..eeb6912acf 100644
--- a/Code/Editor/Util/FileUtil.cpp
+++ b/Code/Editor/Util/FileUtil.cpp
@@ -149,12 +149,13 @@ bool CFileUtil::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const c
// Check if in pack.
if (cryfile.IsInPak())
{
- const char* sPakName = cryfile.GetPakPath();
-
if (bMsgBoxAskForExtraction)
{
+ AZ::IO::FixedMaxPath sPakName{ cryfile.GetPakPath() };
// Cannot edit file in pack, suggest to extract it for editing.
- if (QMessageBox::critical(QApplication::activeWindow(), QString(), QObject::tr("File %1 is inside a PAK file %2\r\nDo you want it to be extracted for editing ?").arg(file, sPakName), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ if (QMessageBox::critical(QApplication::activeWindow(), QString(),
+ QObject::tr("File %1 is inside a PAK file %2\r\nDo you want it to be extracted for editing ?").arg(file, sPakName.c_str()),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
{
return false;
}
@@ -173,10 +174,9 @@ bool CFileUtil::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const c
if (diskFile.open(QFile::WriteOnly))
{
// Copy data from packed file to disk file.
- char* data = new char[cryfile.GetLength()];
- cryfile.ReadRaw(data, cryfile.GetLength());
- diskFile.write(data, cryfile.GetLength());
- delete []data;
+ auto data = AZStd::make_unique(cryfile.GetLength());
+ cryfile.ReadRaw(data.get(), cryfile.GetLength());
+ diskFile.write(data.get(), cryfile.GetLength());
}
else
{
@@ -185,7 +185,14 @@ bool CFileUtil::ExtractFile(QString& file, bool bMsgBoxAskForExtraction, const c
}
else
{
- file = cryfile.GetAdjustedFilename();
+
+ if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr)
+ {
+ if (AZ::IO::FixedMaxPath resolvedFilePath; fileIoBase->ResolvePath(resolvedFilePath, cryfile.GetFilename()))
+ {
+ file = QString::fromUtf8(resolvedFilePath.c_str(), static_cast(resolvedFilePath.Native().size()));
+ }
+ }
}
return true;
@@ -2157,13 +2164,13 @@ uint32 CFileUtil::GetAttributes(const char* filename, bool bUseSourceControl /*=
return SCC_FILE_ATTRIBUTE_READONLY | SCC_FILE_ATTRIBUTE_INPAK;
}
- const char* adjustedFile = file.GetAdjustedFilename();
- if (!AZ::IO::SystemFile::Exists(adjustedFile))
+ auto fileIoBase = AZ::IO::FileIOBase::GetInstance();
+ if (!fileIoBase->Exists(file.GetFilename()))
{
return SCC_FILE_ATTRIBUTE_INVALID;
}
- if (!AZ::IO::SystemFile::IsWritable(adjustedFile))
+ if (fileIoBase->IsReadOnly(file.GetFilename()))
{
return SCC_FILE_ATTRIBUTE_NORMAL | SCC_FILE_ATTRIBUTE_READONLY;
}
diff --git a/Code/Editor/Util/PakFile.cpp b/Code/Editor/Util/PakFile.cpp
index fc8431ef24..b629b45f74 100644
--- a/Code/Editor/Util/PakFile.cpp
+++ b/Code/Editor/Util/PakFile.cpp
@@ -68,7 +68,7 @@ bool CPakFile::Open(const char* filename, bool bAbsolutePath)
if (bAbsolutePath)
{
- m_pArchive = pCryPak->OpenArchive(filename, nullptr, AZ::IO::INestedArchive::FLAGS_ABSOLUTE_PATHS);
+ m_pArchive = pCryPak->OpenArchive(filename, {}, AZ::IO::INestedArchive::FLAGS_ABSOLUTE_PATHS);
}
else
{
@@ -93,7 +93,7 @@ bool CPakFile::OpenForRead(const char* filename)
{
return false;
}
- m_pArchive = pCryPak->OpenArchive(filename, nullptr, AZ::IO::INestedArchive::FLAGS_OPTIMIZED_READ_ONLY | AZ::IO::INestedArchive::FLAGS_ABSOLUTE_PATHS);
+ m_pArchive = pCryPak->OpenArchive(filename, {}, AZ::IO::INestedArchive::FLAGS_OPTIMIZED_READ_ONLY | AZ::IO::INestedArchive::FLAGS_ABSOLUTE_PATHS);
if (m_pArchive)
{
return true;
diff --git a/Code/Editor/Util/Variable.h b/Code/Editor/Util/Variable.h
index 9c3f96a3f6..639161775c 100644
--- a/Code/Editor/Util/Variable.h
+++ b/Code/Editor/Util/Variable.h
@@ -379,11 +379,11 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
virtual ~CVariableBase() {}
- void SetName(const QString& name) { m_name = name; };
+ void SetName(const QString& name) override { m_name = name; };
//! Get name of parameter.
- QString GetName() const { return m_name; };
+ QString GetName() const override { return m_name; };
- QString GetHumanName() const
+ QString GetHumanName() const override
{
if (!m_humanName.isEmpty())
{
@@ -391,82 +391,82 @@ public:
}
return m_name;
}
- void SetHumanName(const QString& name) { m_humanName = name; }
+ void SetHumanName(const QString& name) override { m_humanName = name; }
- void SetDescription(const char* desc) { m_description = desc; };
- void SetDescription(const QString& desc) { m_description = desc; };
+ void SetDescription(const char* desc) override { m_description = desc; };
+ void SetDescription(const QString& desc) override { m_description = desc; };
//! Get name of parameter.
- QString GetDescription() const { return m_description; };
+ QString GetDescription() const override { return m_description; };
- EType GetType() const { return IVariable::UNKNOWN; };
- int GetSize() const { return sizeof(*this); };
+ EType GetType() const override { return IVariable::UNKNOWN; };
+ int GetSize() const override { return sizeof(*this); };
- unsigned char GetDataType() const { return m_dataType; };
- void SetDataType(unsigned char dataType) { m_dataType = dataType; }
+ unsigned char GetDataType() const override { return m_dataType; };
+ void SetDataType(unsigned char dataType) override { m_dataType = dataType; }
- void SetFlags(int flags) { m_flags = static_cast(flags); }
- int GetFlags() const { return m_flags; }
- void SetFlagRecursive(EFlags flag) { m_flags |= flag; }
+ void SetFlags(int flags) override { m_flags = static_cast(flags); }
+ int GetFlags() const override { return m_flags; }
+ void SetFlagRecursive(EFlags flag) override { m_flags |= flag; }
- void SetUserData(const QVariant &data){ m_userData = data; };
- QVariant GetUserData() const { return m_userData; }
+ void SetUserData(const QVariant &data) override { m_userData = data; };
+ QVariant GetUserData() const override { return m_userData; }
//////////////////////////////////////////////////////////////////////////
// Set methods.
//////////////////////////////////////////////////////////////////////////
- void Set([[maybe_unused]] int value) { assert(0); }
- void Set([[maybe_unused]] bool value) { assert(0); }
- void Set([[maybe_unused]] float value) { assert(0); }
- void Set([[maybe_unused]] double value) { assert(0); }
- void Set([[maybe_unused]] const Vec2& value) { assert(0); }
- void Set([[maybe_unused]] const Vec3& value) { assert(0); }
- void Set([[maybe_unused]] const Vec4& value) { assert(0); }
- void Set([[maybe_unused]] const Ang3& value) { assert(0); }
- void Set([[maybe_unused]] const Quat& value) { assert(0); }
- void Set([[maybe_unused]] const QString& value) { assert(0); }
- void Set([[maybe_unused]] const char* value) { assert(0); }
- void SetDisplayValue(const QString& value) { Set(value); }
+ void Set([[maybe_unused]] int value) override { assert(0); }
+ void Set([[maybe_unused]] bool value) override { assert(0); }
+ void Set([[maybe_unused]] float value) override { assert(0); }
+ void Set([[maybe_unused]] double value) override { assert(0); }
+ void Set([[maybe_unused]] const Vec2& value) override { assert(0); }
+ void Set([[maybe_unused]] const Vec3& value) override { assert(0); }
+ void Set([[maybe_unused]] const Vec4& value) override { assert(0); }
+ void Set([[maybe_unused]] const Ang3& value) override { assert(0); }
+ void Set([[maybe_unused]] const Quat& value) override { assert(0); }
+ void Set([[maybe_unused]] const QString& value) override { assert(0); }
+ void Set([[maybe_unused]] const char* value) override { assert(0); }
+ void SetDisplayValue(const QString& value) override { Set(value); }
//////////////////////////////////////////////////////////////////////////
// Get methods.
//////////////////////////////////////////////////////////////////////////
- void Get([[maybe_unused]] int& value) const { assert(0); }
- void Get([[maybe_unused]] bool& value) const { assert(0); }
- void Get([[maybe_unused]] float& value) const { assert(0); }
- void Get([[maybe_unused]] double& value) const { assert(0); }
- void Get([[maybe_unused]] Vec2& value) const { assert(0); }
- void Get([[maybe_unused]] Vec3& value) const { assert(0); }
- void Get([[maybe_unused]] Vec4& value) const { assert(0); }
- void Get([[maybe_unused]] Ang3& value) const { assert(0); }
- void Get([[maybe_unused]] Quat& value) const { assert(0); }
- void Get([[maybe_unused]] QString& value) const { assert(0); }
- QString GetDisplayValue() const { QString val; Get(val); return val; }
+ void Get([[maybe_unused]] int& value) const override { assert(0); }
+ void Get([[maybe_unused]] bool& value) const override { assert(0); }
+ void Get([[maybe_unused]] float& value) const override { assert(0); }
+ void Get([[maybe_unused]] double& value) const override { assert(0); }
+ void Get([[maybe_unused]] Vec2& value) const override { assert(0); }
+ void Get([[maybe_unused]] Vec3& value) const override { assert(0); }
+ void Get([[maybe_unused]] Vec4& value) const override { assert(0); }
+ void Get([[maybe_unused]] Ang3& value) const override { assert(0); }
+ void Get([[maybe_unused]] Quat& value) const override { assert(0); }
+ void Get([[maybe_unused]] QString& value) const override { assert(0); }
+ QString GetDisplayValue() const override { QString val; Get(val); return val; }
//////////////////////////////////////////////////////////////////////////
// IVariableContainer functions
//////////////////////////////////////////////////////////////////////////
- virtual void AddVariable([[maybe_unused]] IVariable* var) { assert(0); }
+ void AddVariable([[maybe_unused]] IVariable* var) override { assert(0); }
- virtual bool DeleteVariable([[maybe_unused]] IVariable* var, [[maybe_unused]] bool recursive = false) { return false; }
- virtual void DeleteAllVariables() {}
+ bool DeleteVariable([[maybe_unused]] IVariable* var, [[maybe_unused]] bool recursive = false) override { return false; }
+ void DeleteAllVariables() override {}
- virtual int GetNumVariables() const { return 0; }
- virtual IVariable* GetVariable([[maybe_unused]] int index) const { return nullptr; }
+ int GetNumVariables() const override { return 0; }
+ IVariable* GetVariable([[maybe_unused]] int index) const override { return nullptr; }
- virtual bool IsContainsVariable([[maybe_unused]] IVariable* pVar, [[maybe_unused]] bool bRecursive = false) const { return false; }
+ bool IsContainsVariable([[maybe_unused]] IVariable* pVar, [[maybe_unused]] bool bRecursive = false) const override { return false; }
- virtual IVariable* FindVariable([[maybe_unused]] const char* name, [[maybe_unused]] bool bRecursive = false, [[maybe_unused]] bool bHumanName = false) const { return nullptr; }
+ IVariable* FindVariable([[maybe_unused]] const char* name, [[maybe_unused]] bool bRecursive = false, [[maybe_unused]] bool bHumanName = false) const override { return nullptr; }
- virtual bool IsEmpty() const { return true; }
+ bool IsEmpty() const override { return true; }
//////////////////////////////////////////////////////////////////////////
- void Wire(IVariable* var)
+ void Wire(IVariable* var) override
{
m_wiredVars.push_back(var);
}
//////////////////////////////////////////////////////////////////////////
- void Unwire(IVariable* var)
+ void Unwire(IVariable* var) override
{
if (!var)
{
@@ -480,7 +480,7 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- void AddOnSetCallback(OnSetCallback* func)
+ void AddOnSetCallback(OnSetCallback* func) override
{
if (!stl::find(m_onSetFuncs, func))
{
@@ -489,13 +489,13 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- void RemoveOnSetCallback(OnSetCallback* func)
+ void RemoveOnSetCallback(OnSetCallback* func) override
{
stl::find_and_erase(m_onSetFuncs, func);
}
//////////////////////////////////////////////////////////////////////////
- void ClearOnSetCallbacks()
+ void ClearOnSetCallbacks() override
{
m_onSetFuncs.clear();
}
@@ -509,7 +509,7 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- void RemoveOnSetEnumCallback(OnSetCallback* func)
+ void RemoveOnSetEnumCallback(OnSetCallback* func) override
{
stl::find_and_erase(m_onSetEnumFuncs, func);
}
@@ -520,7 +520,7 @@ public:
}
- virtual void OnSetValue([[maybe_unused]] bool bRecursive)
+ void OnSetValue([[maybe_unused]] bool bRecursive) override
{
// If have wired variables or OnSet callback, process them.
// Send value to wired variable.
@@ -549,7 +549,8 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- void Serialize(XmlNodeRef node, bool load)
+ using IVariable::Serialize;
+ void Serialize(XmlNodeRef node, bool load) override
{
if (load)
{
@@ -567,8 +568,8 @@ public:
}
}
- virtual void EnableUpdateCallbacks(bool boEnable){m_boUpdateCallbacksEnabled = boEnable; };
- virtual void SetForceModified(bool bForceModified) { m_bForceModified = bForceModified; }
+ void EnableUpdateCallbacks(bool boEnable) override{m_boUpdateCallbacksEnabled = boEnable; };
+ void SetForceModified(bool bForceModified) override { m_bForceModified = bForceModified; }
protected:
// Constructor.
CVariableBase()
@@ -641,13 +642,13 @@ public:
CVariableArray(){}
//! Get name of parameter.
- virtual EType GetType() const { return IVariable::ARRAY; };
- virtual int GetSize() const { return sizeof(CVariableArray); };
+ EType GetType() const override { return IVariable::ARRAY; };
+ int GetSize() const override { return sizeof(CVariableArray); };
//////////////////////////////////////////////////////////////////////////
// Set methods.
//////////////////////////////////////////////////////////////////////////
- virtual void Set(const QString& value)
+ void Set(const QString& value) override
{
if (m_strValue != value)
{
@@ -655,7 +656,7 @@ public:
OnSetValue(false);
}
}
- void OnSetValue(bool bRecursive)
+ void OnSetValue(bool bRecursive) override
{
CVariableBase::OnSetValue(bRecursive);
if (bRecursive)
@@ -666,7 +667,7 @@ public:
}
}
}
- void SetFlagRecursive(EFlags flag)
+ void SetFlagRecursive(EFlags flag) override
{
CVariableBase::SetFlagRecursive(flag);
for (Variables::iterator it = m_vars.begin(); it != m_vars.end(); ++it)
@@ -677,9 +678,9 @@ public:
//////////////////////////////////////////////////////////////////////////
// Get methods.
//////////////////////////////////////////////////////////////////////////
- virtual void Get(QString& value) const { value = m_strValue; }
+ void Get(QString& value) const override { value = m_strValue; }
- virtual bool HasDefaultValue() const
+ bool HasDefaultValue() const override
{
for (Variables::const_iterator it = m_vars.begin(); it != m_vars.end(); ++it)
{
@@ -691,7 +692,7 @@ public:
return true;
}
- virtual void ResetToDefault()
+ void ResetToDefault() override
{
for (Variables::const_iterator it = m_vars.begin(); it != m_vars.end(); ++it)
{
@@ -700,7 +701,7 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- IVariable* Clone(bool bRecursive) const
+ IVariable* Clone(bool bRecursive) const override
{
CVariableArray* var = new CVariableArray(*this);
@@ -713,7 +714,7 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- void CopyValue(IVariable* fromVar)
+ void CopyValue(IVariable* fromVar) override
{
assert(fromVar);
if (fromVar->GetType() != IVariable::ARRAY)
@@ -733,20 +734,20 @@ public:
}
//////////////////////////////////////////////////////////////////////////
- virtual int GetNumVariables() const { return static_cast(m_vars.size()); }
+ int GetNumVariables() const override { return static_cast(m_vars.size()); }
- virtual IVariable* GetVariable(int index) const
+ IVariable* GetVariable(int index) const override
{
assert(index >= 0 && index < (int)m_vars.size());
return m_vars[index];
}
- virtual void AddVariable(IVariable* var)
+ void AddVariable(IVariable* var) override
{
m_vars.push_back(var);
}
- virtual bool DeleteVariable(IVariable* var, bool recursive /*=false*/)
+ bool DeleteVariable(IVariable* var, bool recursive /*=false*/) override
{
bool found = stl::find_and_erase(m_vars, var);
if (!found && recursive)
@@ -762,12 +763,12 @@ public:
return found;
}
- virtual void DeleteAllVariables()
+ void DeleteAllVariables() override
{
m_vars.clear();
}
- virtual bool IsContainsVariable(IVariable* pVar, bool bRecursive) const
+ bool IsContainsVariable(IVariable* pVar, bool bRecursive) const override
{
for (Variables::const_iterator it = m_vars.begin(); it != m_vars.end(); ++it)
{
@@ -793,14 +794,15 @@ public:
return false;
}
- virtual IVariable* FindVariable(const char* name, bool bRecursive, bool bHumanName) const;
+ IVariable* FindVariable(const char* name, bool bRecursive, bool bHumanName) const override;
- virtual bool IsEmpty() const
+ bool IsEmpty() const override
{
return m_vars.empty();
}
- void Serialize(XmlNodeRef node, bool load)
+ using IVariable::Serialize;
+ void Serialize(XmlNodeRef node, bool load) override
{
if (load)
{
@@ -1074,11 +1076,11 @@ class CVariableVoid
{
public:
CVariableVoid(){};
- virtual EType GetType() const { return IVariable::UNKNOWN; };
- virtual IVariable* Clone([[maybe_unused]] bool bRecursive) const { return new CVariableVoid(*this); }
- virtual void CopyValue([[maybe_unused]] IVariable* fromVar) {};
- virtual bool HasDefaultValue() const { return true; }
- virtual void ResetToDefault() {};
+ EType GetType() const override { return IVariable::UNKNOWN; };
+ IVariable* Clone([[maybe_unused]] bool bRecursive) const override { return new CVariableVoid(*this); }
+ void CopyValue([[maybe_unused]] IVariable* fromVar) override {};
+ bool HasDefaultValue() const override { return true; }
+ void ResetToDefault() override {};
protected:
CVariableVoid(const CVariableVoid& v)
: CVariableBase(v) {};
@@ -1112,44 +1114,44 @@ public:
}
//! Get name of parameter.
- virtual EType GetType() const { return (EType)var_type::type_traits::type(); };
- virtual int GetSize() const { return sizeof(T); };
+ EType GetType() const override { return (EType)var_type::type_traits::type(); };
+ int GetSize() const override { return sizeof(T); };
//////////////////////////////////////////////////////////////////////////
// Set methods.
//////////////////////////////////////////////////////////////////////////
- virtual void Set(int value) { SetValue(value); }
- virtual void Set(bool value) { SetValue(value); }
- virtual void Set(float value) { SetValue(value); }
- virtual void Set(double value) { SetValue(value); }
- virtual void Set(const Vec2& value) { SetValue(value); }
- virtual void Set(const Vec3& value) { SetValue(value); }
- virtual void Set(const Vec4& value) { SetValue(value); }
- virtual void Set(const Ang3& value) { SetValue(value); }
- virtual void Set(const Quat& value) { SetValue(value); }
- virtual void Set(const QString& value) { SetValue(value); }
- virtual void Set(const char* value) { SetValue(QString(value)); }
+ void Set(int value) override { SetValue(value); }
+ void Set(bool value) override { SetValue(value); }
+ void Set(float value) override { SetValue(value); }
+ void Set(double value) override { SetValue(value); }
+ void Set(const Vec2& value) override { SetValue(value); }
+ void Set(const Vec3& value) override { SetValue(value); }
+ void Set(const Vec4& value) override { SetValue(value); }
+ void Set(const Ang3& value) override { SetValue(value); }
+ void Set(const Quat& value) override { SetValue(value); }
+ void Set(const QString& value) override { SetValue(value); }
+ void Set(const char* value) override { SetValue(QString(value)); }
//////////////////////////////////////////////////////////////////////////
// Get methods.
//////////////////////////////////////////////////////////////////////////
- virtual void Get(int& value) const { GetValue(value); }
- virtual void Get(bool& value) const { GetValue(value); }
- virtual void Get(float& value) const { GetValue(value); }
- virtual void Get(double& value) const { GetValue(value); }
- virtual void Get(Vec2& value) const { GetValue(value); }
- virtual void Get(Vec3& value) const { GetValue(value); }
- virtual void Get(Vec4& value) const { GetValue(value); }
- virtual void Get(Quat& value) const { GetValue(value); }
- virtual void Get(QString& value) const { GetValue(value); }
- virtual bool HasDefaultValue() const
+ void Get(int& value) const override { GetValue(value); }
+ void Get(bool& value) const override { GetValue(value); }
+ void Get(float& value) const override { GetValue(value); }
+ void Get(double& value) const override { GetValue(value); }
+ void Get(Vec2& value) const override { GetValue(value); }
+ void Get(Vec3& value) const override { GetValue(value); }
+ void Get(Vec4& value) const override { GetValue(value); }
+ void Get(Quat& value) const override { GetValue(value); }
+ void Get(QString& value) const override { GetValue(value); }
+ bool HasDefaultValue() const override
{
T defval;
var_type::init(defval);
return m_valueDef == defval;
}
- virtual void ResetToDefault()
+ void ResetToDefault() override
{
T defval;
var_type::init(defval);
@@ -1159,7 +1161,7 @@ public:
//////////////////////////////////////////////////////////////////////////
// Limits.
//////////////////////////////////////////////////////////////////////////
- virtual void SetLimits(float fMin, float fMax, float fStep = 0.f, bool bHardMin = true, bool bHardMax = true)
+ void SetLimits(float fMin, float fMax, float fStep = 0.f, bool bHardMin = true, bool bHardMax = true) override
{
m_valueMin = fMin;
m_valueMax = fMax;
@@ -1171,7 +1173,7 @@ public:
m_customLimits = true;
}
- virtual void GetLimits(float& fMin, float& fMax, float& fStep, bool& bHardMin, bool& bHardMax)
+ void GetLimits(float& fMin, float& fMax, float& fStep, bool& bHardMin, bool& bHardMax) override
{
if (!m_customLimits && var_type::type_traits::supports_range())
{
@@ -1199,7 +1201,7 @@ public:
m_customLimits = false;
}
- virtual bool HasCustomLimits()
+ bool HasCustomLimits() override
{
return m_customLimits;
}
@@ -1217,14 +1219,14 @@ public:
void operator=(const T& value) { SetValue(value); }
//////////////////////////////////////////////////////////////////////////
- IVariable* Clone([[maybe_unused]] bool bRecursive) const
+ IVariable* Clone([[maybe_unused]] bool bRecursive) const override
{
Self* var = new Self(*this);
return var;
}
//////////////////////////////////////////////////////////////////////////
- void CopyValue(IVariable* fromVar)
+ void CopyValue(IVariable* fromVar) override
{
assert(fromVar);
T val;
@@ -1668,7 +1670,7 @@ struct CSmartVariableBase
return *pV;
} // Cast to CVariableBase&
VarType& operator*() const { return *pVar; }
- VarType* operator->(void) const { return pVar; }
+ VarType* operator->() const { return pVar; }
VarType* GetVar() const { return pVar; };
@@ -1730,7 +1732,7 @@ struct CSmartVariableArray
}
VarType& operator*() const { return *pVar; }
- VarType* operator->(void) const { return pVar; }
+ VarType* operator->() const { return pVar; }
VarType* GetVar() const { return pVar; };
@@ -1752,35 +1754,35 @@ public:
// Dtor.
virtual ~CVarBlock() {}
//! Add variable to block.
- virtual void AddVariable(IVariable* var);
+ void AddVariable(IVariable* var) override;
//! Remove variable from block
- virtual bool DeleteVariable(IVariable* var, bool bRecursive = false);
+ bool DeleteVariable(IVariable* var, bool bRecursive = false) override;
void AddVariable(IVariable* pVar, const char* varName, unsigned char dataType = IVariable::DT_SIMPLE);
// This used from smart variable pointer.
void AddVariable(CVariableBase& var, const char* varName, unsigned char dataType = IVariable::DT_SIMPLE);
//! Returns number of variables in block.
- virtual int GetNumVariables() const { return static_cast(m_vars.size()); }
+ int GetNumVariables() const override { return static_cast(m_vars.size()); }
//! Get pointer to stored variable by index.
- virtual IVariable* GetVariable(int index) const
+ IVariable* GetVariable(int index) const override
{
assert(index >= 0 && index < m_vars.size());
return m_vars[index];
}
// Clear all vars from VarBlock.
- virtual void DeleteAllVariables() { m_vars.clear(); };
+ void DeleteAllVariables() override { m_vars.clear(); };
//! Return true if variable block is empty (Does not have any vars).
- virtual bool IsEmpty() const { return m_vars.empty(); }
+ bool IsEmpty() const override { return m_vars.empty(); }
// Returns true if var block contains specified variable.
- virtual bool IsContainsVariable(IVariable* pVar, bool bRecursive = true) const;
+ bool IsContainsVariable(IVariable* pVar, bool bRecursive = true) const override;
//! Find variable by name.
- virtual IVariable* FindVariable(const char* name, bool bRecursive = true, bool bHumanName = false) const;
+ IVariable* FindVariable(const char* name, bool bRecursive = true, bool bHumanName = false) const override;
//////////////////////////////////////////////////////////////////////////
//! Clone var block.
diff --git a/Code/Editor/Util/XmlArchive.cpp b/Code/Editor/Util/XmlArchive.cpp
index e6bc93fdf4..18c3fc8e63 100644
--- a/Code/Editor/Util/XmlArchive.cpp
+++ b/Code/Editor/Util/XmlArchive.cpp
@@ -124,7 +124,7 @@ bool CXmlArchive::SaveToPak([[maybe_unused]] const QString& levelPath, CPakFile&
if (pakFile.GetArchive())
{
- CLogFile::FormatLine("Saving pak file %s", (const char*)pakFile.GetArchive()->GetFullPath());
+ CLogFile::FormatLine("Saving pak file %.*s", AZ_STRING_ARG(pakFile.GetArchive()->GetFullPath().Native()));
}
pNamedData->Save(pakFile);
diff --git a/Code/Editor/Viewport.h b/Code/Editor/Viewport.h
index 74897508f0..60c1306420 100644
--- a/Code/Editor/Viewport.h
+++ b/Code/Editor/Viewport.h
@@ -172,7 +172,7 @@ public:
//! Get current view matrix.
//! This is a matrix that transforms from world space to view space.
- virtual const Matrix34& GetViewTM() const
+ const Matrix34& GetViewTM() const override
{
AZ_Error("CryLegacy", false, "QtViewport::GetViewTM not implemented");
static const Matrix34 m;
@@ -182,7 +182,7 @@ public:
//////////////////////////////////////////////////////////////////////////
//! Get current screen matrix.
//! Screen matrix transform from World space to Screen space.
- virtual const Matrix34& GetScreenTM() const
+ const Matrix34& GetScreenTM() const override
{
return m_screenTM;
}
@@ -190,9 +190,9 @@ public:
virtual Vec3 MapViewToCP(const QPoint& point) = 0;
//! Map viewport position to world space position.
- virtual Vec3 ViewToWorld(const QPoint& vp, bool* pCollideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const = 0;
+ Vec3 ViewToWorld(const QPoint& vp, bool* pCollideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override = 0;
//! Convert point on screen to world ray.
- virtual void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const = 0;
+ void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const override = 0;
//! Get normal for viewport position
virtual Vec3 ViewToWorldNormal(const QPoint& vp, bool onlyTerrain, bool bTestRenderMesh = false) = 0;
@@ -261,7 +261,7 @@ public:
virtual void SetCursorString(const QString& str) = 0;
virtual void SetFocus() = 0;
- virtual void Invalidate(bool bErase = 1) = 0;
+ virtual void Invalidate(bool bErase = true) = 0;
// Is overridden by RenderViewport
virtual void SetFOV([[maybe_unused]] float fov) {}
@@ -274,7 +274,7 @@ public:
void SetViewPane(CLayoutViewPane* viewPane) { m_viewPane = viewPane; }
- virtual CViewport *asCViewport() { return this; }
+ CViewport *asCViewport() override { return this; }
protected:
CLayoutViewPane* m_viewPane = nullptr;
@@ -336,7 +336,7 @@ public:
void SetActiveWindow() override { activateWindow(); }
//! Called while window is idle.
- virtual void Update();
+ void Update() override;
/** Set name of this viewport.
*/
@@ -344,24 +344,24 @@ public:
/** Get name of viewport
*/
- QString GetName() const;
+ QString GetName() const override;
- virtual void SetFocus() { setFocus(); }
- virtual void Invalidate([[maybe_unused]] bool bErase = 1) { update(); }
+ void SetFocus() override { setFocus(); }
+ void Invalidate([[maybe_unused]] bool bErase = 1) override { update(); }
// Is overridden by RenderViewport
- virtual void SetFOV([[maybe_unused]] float fov) {}
- virtual float GetFOV() const;
+ void SetFOV([[maybe_unused]] float fov) override {}
+ float GetFOV() const override;
// Must be overridden in derived classes.
// Returns:
// e.g. 4.0/3.0
- virtual float GetAspectRatio() const = 0;
- virtual void GetDimensions(int* pWidth, int* pHeight) const;
- virtual void ScreenToClient(QPoint& pPoint) const override;
+ float GetAspectRatio() const override = 0;
+ void GetDimensions(int* pWidth, int* pHeight) const override;
+ void ScreenToClient(QPoint& pPoint) const override;
- virtual void ResetContent();
- virtual void UpdateContent(int flags);
+ void ResetContent() override;
+ void UpdateContent(int flags) override;
//! Set current zoom factor for this viewport.
virtual void SetZoomFactor(float fZoomFactor);
@@ -373,10 +373,10 @@ public:
virtual void OnDeactivate();
//! Map world space position to viewport position.
- virtual QPoint WorldToView(const Vec3& wp) const override;
+ QPoint WorldToView(const Vec3& wp) const override;
//! Map world space position to 3D viewport position.
- virtual Vec3 WorldToView3D(const Vec3& wp, int nFlags = 0) const;
+ Vec3 WorldToView3D(const Vec3& wp, int nFlags = 0) const override;
//! Map viewport position to world space position.
virtual Vec3 ViewToWorld(const QPoint& vp, bool* pCollideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override;
@@ -391,17 +391,18 @@ public:
//! This method return a vector (p2-p1) in world space alligned to construction plane and restriction axises.
//! p1 and p2 must be given in world space and lie on construction plane.
- virtual Vec3 GetCPVector(const Vec3& p1, const Vec3& p2, int axis);
+ using CViewport::GetCPVector;
+ Vec3 GetCPVector(const Vec3& p1, const Vec3& p2, int axis) override;
//! Snap any given 3D world position to grid lines if snap is enabled.
Vec3 SnapToGrid(const Vec3& vec) override;
- virtual float GetGridStep() const;
+ float GetGridStep() const override;
//! Returns the screen scale factor for a point given in world coordinates.
//! This factor gives the width in world-space units at the point's distance of the viewport.
- virtual float GetScreenScaleFactor([[maybe_unused]] const Vec3& worldPoint) const { return 1; };
+ float GetScreenScaleFactor([[maybe_unused]] const Vec3& worldPoint) const override { return 1; };
- void SetAxisConstrain(int axis);
+ void SetAxisConstrain(int axis) override;
/// Take raw input and create a final mouse interaction.
/// @attention Do not map **point** from widget to viewport explicitly,
@@ -413,7 +414,7 @@ public:
// Selection.
//////////////////////////////////////////////////////////////////////////
//! Resets current selection region.
- virtual void ResetSelectionRegion();
+ void ResetSelectionRegion() override;
//! Set 2D selection rectangle.
void SetSelectionRectangle(const QRect& rect) override;
@@ -422,12 +423,12 @@ public:
//! Called when dragging selection rectangle.
void OnDragSelectRectangle(const QRect& rect, bool bNormalizeRect = false) override;
//! Get selection precision tolerance.
- float GetSelectionTolerance() const { return m_selectionTolerance; }
+ float GetSelectionTolerance() const override { return m_selectionTolerance; }
//! Center viewport on selection.
void CenterOnSelection() override {}
void CenterOnAABB([[maybe_unused]] const AABB& aabb) override {}
- virtual void CenterOnSliceInstance() {}
+ void CenterOnSliceInstance() override {}
//! Performs hit testing of 2d point in view to find which object hit.
bool HitTest(const QPoint& point, HitContext& hitInfo) override;
@@ -440,10 +441,10 @@ public:
float GetDistanceToLine(const Vec3& lineP1, const Vec3& lineP2, const QPoint& point) const override;
// Access to the member m_bAdvancedSelectMode so interested modules can know its value.
- bool GetAdvancedSelectModeFlag();
+ bool GetAdvancedSelectModeFlag() override;
- virtual void GetPerpendicularAxis(EAxis* pAxis, bool* pIs2D) const;
- virtual const ::Plane* GetConstructionPlane() const { return &m_constructionPlane; }
+ void GetPerpendicularAxis(EAxis* pAxis, bool* pIs2D) const override;
+ const ::Plane* GetConstructionPlane() const override { return &m_constructionPlane; }
//////////////////////////////////////////////////////////////////////////
@@ -451,7 +452,7 @@ public:
//! Set construction plane from given position construction matrix refrence coord system and axis settings.
//////////////////////////////////////////////////////////////////////////
void MakeConstructionPlane(int axis) override;
- virtual void SetConstructionMatrix(RefCoordSys coordSys, const Matrix34& xform);
+ void SetConstructionMatrix(RefCoordSys coordSys, const Matrix34& xform) override;
virtual const Matrix34& GetConstructionMatrix(RefCoordSys coordSys);
// Set simple construction plane origin.
void SetConstructionOrigin(const Vec3& worldPos);
@@ -461,11 +462,11 @@ public:
//////////////////////////////////////////////////////////////////////////
// Undo for viewpot operations.
- void BeginUndo();
- void AcceptUndo(const QString& undoDescription);
- void CancelUndo();
- void RestoreUndo();
- bool IsUndoRecording() const;
+ void BeginUndo() override;
+ void AcceptUndo(const QString& undoDescription) override;
+ void CancelUndo() override;
+ void RestoreUndo() override;
+ bool IsUndoRecording() const override;
//////////////////////////////////////////////////////////////////////////
//! Get prefered original size for this viewport.
@@ -473,39 +474,39 @@ public:
virtual QSize GetIdealSize() const;
//! Check if world space bounding box is visible in this view.
- virtual bool IsBoundsVisible(const AABB& box) const;
+ bool IsBoundsVisible(const AABB& box) const override;
//////////////////////////////////////////////////////////////////////////
- void SetCursor(const QCursor& cursor)
+ void SetCursor(const QCursor& cursor) override
{
setCursor(cursor);
}
// Set`s current cursor string.
void SetCurrentCursor(const QCursor& hCursor, const QString& cursorString);
- virtual void SetCurrentCursor(EStdCursor stdCursor, const QString& cursorString);
- void SetCurrentCursor(EStdCursor stdCursor);
- virtual void SetCursorString(const QString& cursorString);
- void ResetCursor();
- void SetSupplementaryCursorStr(const QString& str);
+ void SetCurrentCursor(EStdCursor stdCursor, const QString& cursorString) override;
+ void SetCurrentCursor(EStdCursor stdCursor) override;
+ void SetCursorString(const QString& cursorString) override;
+ void ResetCursor() override;
+ void SetSupplementaryCursorStr(const QString& str) override;
//////////////////////////////////////////////////////////////////////////
// Return visble objects cache.
- CBaseObjectsCache* GetVisibleObjectsCache() { return m_pVisibleObjectsCache; };
+ CBaseObjectsCache* GetVisibleObjectsCache() override { return m_pVisibleObjectsCache; };
- void RegisterRenderListener(IRenderListener* piListener);
- bool UnregisterRenderListener(IRenderListener* piListener);
- bool IsRenderListenerRegistered(IRenderListener* piListener);
+ void RegisterRenderListener(IRenderListener* piListener) override;
+ bool UnregisterRenderListener(IRenderListener* piListener) override;
+ bool IsRenderListenerRegistered(IRenderListener* piListener) override;
- void AddPostRenderer(IPostRenderer* pPostRenderer);
- bool RemovePostRenderer(IPostRenderer* pPostRenderer);
+ void AddPostRenderer(IPostRenderer* pPostRenderer) override;
+ bool RemovePostRenderer(IPostRenderer* pPostRenderer) override;
void CaptureMouse() override { m_mouseCaptured = true; QWidget::grabMouse(); }
void ReleaseMouse() override { m_mouseCaptured = false; QWidget::releaseMouse(); }
- virtual void setRay(QPoint& vp, Vec3& raySrc, Vec3& rayDir);
- virtual void setHitcontext(QPoint& vp, Vec3& raySrc, Vec3& rayDir);
+ void setRay(QPoint& vp, Vec3& raySrc, Vec3& rayDir) override;
+ void setHitcontext(QPoint& vp, Vec3& raySrc, Vec3& rayDir) override;
QPoint m_vp;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
Vec3 m_raySrc;
diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp
index 1f04f71712..65d6de8944 100644
--- a/Code/Editor/ViewportTitleDlg.cpp
+++ b/Code/Editor/ViewportTitleDlg.cpp
@@ -154,6 +154,8 @@ void CViewportTitleDlg::SetupCameraDropdownMenu()
cameraMenu->addMenu(GetFovMenu());
m_ui->m_cameraMenu->setMenu(cameraMenu);
m_ui->m_cameraMenu->setPopupMode(QToolButton::InstantPopup);
+ QObject::connect(cameraMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::CheckForCameraSpeedUpdate);
+
QAction* gotoPositionAction = new QAction("Go to position", cameraMenu);
connect(gotoPositionAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedGotoPosition);
cameraMenu->addAction(gotoPositionAction);
diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h
index 5acb04ca99..4a2a454907 100644
--- a/Code/Editor/ViewportTitleDlg.h
+++ b/Code/Editor/ViewportTitleDlg.h
@@ -77,7 +77,7 @@ Q_SIGNALS:
protected:
virtual void OnInitDialog();
- virtual void OnEditorNotifyEvent(EEditorNotifyEvent event);
+ void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override;
void OnMaximize();
diff --git a/Code/Framework/AtomCore/AtomCore/Utils/ScopedValue.h b/Code/Framework/AtomCore/AtomCore/Utils/ScopedValue.h
new file mode 100644
index 0000000000..f6ed6d6df4
--- /dev/null
+++ b/Code/Framework/AtomCore/AtomCore/Utils/ScopedValue.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+#include
+
+namespace AZ
+{
+ //! Sets a variable upon construction and again when the object goes out of scope.
+ template
+ class ScopedValue
+ {
+ private:
+ T* m_ptr;
+ T m_finalValue;
+
+ public:
+ ScopedValue(T* ptr, T initialValue, T finalValue) :
+ m_ptr(ptr), m_finalValue(finalValue)
+ {
+ AZ_Assert(m_ptr, "ScopedValue::m_ptr is null");
+ *m_ptr = initialValue;
+ }
+
+ ~ScopedValue()
+ {
+ *m_ptr = m_finalValue;
+ }
+ };
+
+} // namespace AZ
diff --git a/Code/Framework/AtomCore/AtomCore/atomcore_files.cmake b/Code/Framework/AtomCore/AtomCore/atomcore_files.cmake
index c90263468f..9167c1e645 100644
--- a/Code/Framework/AtomCore/AtomCore/atomcore_files.cmake
+++ b/Code/Framework/AtomCore/AtomCore/atomcore_files.cmake
@@ -19,4 +19,5 @@ set(FILES
std/containers/vector_set.h
std/containers/vector_set_base.h
std/parallel/concurrency_checker.h
+ Utils/ScopedValue.h
)
diff --git a/Code/Framework/AtomCore/Tests/ScopedValueTest.cpp b/Code/Framework/AtomCore/Tests/ScopedValueTest.cpp
new file mode 100644
index 0000000000..9578cb2329
--- /dev/null
+++ b/Code/Framework/AtomCore/Tests/ScopedValueTest.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+
+namespace UnitTest
+{
+ TEST(ScopedValueTest, TestBoolValue)
+ {
+ bool localValue = false;
+
+ {
+ AZ::ScopedValue scopedValue(&localValue, true, false);
+ EXPECT_EQ(true, localValue);
+ }
+
+ EXPECT_EQ(false, localValue);
+ }
+
+ TEST(ScopedValueTest, TestIntValue)
+ {
+ int localValue = 0;
+
+ {
+ AZ::ScopedValue scopedValue(&localValue, 1, 2);
+ EXPECT_EQ(1, localValue);
+ }
+
+ EXPECT_EQ(2, localValue);
+ }
+}
diff --git a/Code/Framework/AtomCore/Tests/atomcore_tests_files.cmake b/Code/Framework/AtomCore/Tests/atomcore_tests_files.cmake
index 0f5fcb441d..4522a4b7b6 100644
--- a/Code/Framework/AtomCore/Tests/atomcore_tests_files.cmake
+++ b/Code/Framework/AtomCore/Tests/atomcore_tests_files.cmake
@@ -12,5 +12,6 @@ set(FILES
InstanceDatabase.cpp
lru_cache.cpp
Main.cpp
+ ScopedValueTest.cpp
vector_set.cpp
)
diff --git a/Code/Framework/AzCore/AzCore/Component/Component.h b/Code/Framework/AzCore/AzCore/Component/Component.h
index 9b4ae3f55f..3cbb9b5a86 100644
--- a/Code/Framework/AzCore/AzCore/Component/Component.h
+++ b/Code/Framework/AzCore/AzCore/Component/Component.h
@@ -266,7 +266,7 @@ namespace AZ
_ComponentClass::RTTI_Type().ToString().c_str(), descriptor->GetName(), _ComponentClass::RTTI_TypeName()); \
return nullptr; \
} \
- else if (descriptor->GetName() != _ComponentClass::RTTI_TypeName()) \
+ if (descriptor->GetName() != _ComponentClass::RTTI_TypeName()) \
{ \
AZ_Error("Component", false, "The same component UUID (%s) / name (%s) was registered twice. This isn't allowed, " \
"it can cause lifetime management issues / crashes.\nThis situation can happen by declaring a component " \
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
index 04a76b0f8e..a13f11c007 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
@@ -1251,6 +1251,8 @@ namespace AZ
return AZ::SettingsRegistryInterface::VisitResponse::Continue;
}
+
+ using SettingsRegistryInterface::Visitor::Visit;
void Visit(AZStd::string_view path, AZStd::string_view valueName, AZ::SettingsRegistryInterface::Type, bool value) override
{
// By default the auto load option is true
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
index 3768a75d83..bfc541ca09 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
@@ -196,14 +196,14 @@ namespace AZ
//////////////////////////////////////////////////////////////////////////
// ComponentApplicationRequests
- void RegisterComponentDescriptor(const ComponentDescriptor* descriptor) override final;
- void UnregisterComponentDescriptor(const ComponentDescriptor* descriptor) override final;
- void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler& handler) override final;
- void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) override final;
- void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) override final;
- void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) override final;
- void SignalEntityActivated(Entity* entity) override final;
- void SignalEntityDeactivated(Entity* entity) override final;
+ void RegisterComponentDescriptor(const ComponentDescriptor* descriptor) final;
+ void UnregisterComponentDescriptor(const ComponentDescriptor* descriptor) final;
+ void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler& handler) final;
+ void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) final;
+ void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) final;
+ void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) final;
+ void SignalEntityActivated(Entity* entity) final;
+ void SignalEntityDeactivated(Entity* entity) final;
bool AddEntity(Entity* entity) override;
bool RemoveEntity(Entity* entity) override;
bool DeleteEntity(const EntityId& id) override;
diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp
index 4febd893b0..0fe201d448 100644
--- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp
@@ -207,12 +207,6 @@ namespace AZ
ActivateComponent(**it);
}
- // Cache the transform interface to the transform interface
- // Generally this pattern is not recommended unless for component event buses
- // As we have a guarantee (by design) that components can't change during active state)
- // Even though technically they can connect disconnect from the bus.
- m_transform = TransformBus::FindFirstHandler(m_id);
-
SetState(State::Active);
EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id);
@@ -1330,6 +1324,19 @@ namespace AZ
return *processSignature;
}
+ AZ::TransformInterface* Entity::GetTransform() const
+ {
+ // Lazy evaluation of the cached entity transform.
+ if(!m_transform)
+ {
+ // Generally this pattern is not recommended unless for component event buses
+ // As we have a guarantee (by design) that components can't change during active state)
+ // Even though technically they can connect disconnect from the bus.
+ m_transform = TransformBus::FindFirstHandler(m_id);
+ }
+ return m_transform;
+ }
+
//=========================================================================
// MakeId
// Ids must be unique across a project at authoring time. Runtime doesn't matter
diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.h b/Code/Framework/AzCore/AzCore/Component/Entity.h
index 3887b2e03e..c2bde375bb 100644
--- a/Code/Framework/AzCore/AzCore/Component/Entity.h
+++ b/Code/Framework/AzCore/AzCore/Component/Entity.h
@@ -362,10 +362,9 @@ namespace AZ
//! @return The Process Signature of the local machine.
static AZ::u32 GetProcessSignature();
- /// @cond EXCLUDE_DOCS
- //! @deprecated Use the TransformBus to communicate with the TransformInterface.
- inline TransformInterface* GetTransform() const { return m_transform; }
- /// @endcond
+ //! Gets the TransformInterface for the entity.
+ //! @return The TransformInterface for the entity.
+ TransformInterface* GetTransform() const;
//! Sorts an entity's components based on the dependencies between components.
//! If all dependencies are met, the required services can be activated
@@ -414,7 +413,7 @@ namespace AZ
//! A cached pointer to the transform interface.
//! We recommend using AZ::TransformBus and caching locally instead of accessing
//! the transform interface directly through this pointer.
- TransformInterface* m_transform;
+ mutable TransformInterface* m_transform;
//! A user-friendly name for the entity. This makes error messages easier to read.
AZStd::string m_name;
diff --git a/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypes.h b/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypes.h
index c46edbb80e..f538c516c3 100644
--- a/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypes.h
+++ b/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypes.h
@@ -86,6 +86,7 @@ namespace AZ
class AssetTreeNodeBase
{
public:
+ virtual ~AssetTreeNodeBase() = default;
virtual const AssetPrimaryInfo* GetAssetPrimaryInfo() const = 0;
virtual AssetTreeNodeBase* FindOrAddChild(const AssetTrackingId& id, const AssetPrimaryInfo* info) = 0;
};
@@ -94,6 +95,7 @@ namespace AZ
class AssetTreeBase
{
public:
+ virtual ~AssetTreeBase() = default;
virtual AssetTreeNodeBase& GetRoot() = 0;
};
@@ -101,6 +103,7 @@ namespace AZ
class AssetAllocationTableBase
{
public:
+ virtual ~AssetAllocationTableBase() = default;
virtual AssetTreeNodeBase* FindAllocation(void* ptr) const = 0;
};
}
diff --git a/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypesImpl.h b/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypesImpl.h
index 7916a442b5..eac809c406 100644
--- a/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypesImpl.h
+++ b/Code/Framework/AzCore/AzCore/Debug/AssetTrackingTypesImpl.h
@@ -31,6 +31,8 @@ namespace AZ
{
}
+ ~AssetTreeNode() override = default;
+
const AssetPrimaryInfo* GetAssetPrimaryInfo() const override
{
return m_primaryinfo;
@@ -67,6 +69,8 @@ namespace AZ
class AssetTree : public AssetTreeBase
{
public:
+ ~AssetTree() override = default;
+
AssetTreeNodeBase& GetRoot() override
{
return m_rootAssets;
@@ -99,6 +103,7 @@ namespace AZ
AllocationTable(mutex_type& mutex) : m_mutex(mutex)
{
}
+ ~AllocationTable() override = default;
AssetTreeNodeBase* FindAllocation(void* ptr) const override
{
diff --git a/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h b/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h
index 1357bb5870..34d8510349 100644
--- a/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h
+++ b/Code/Framework/AzCore/AzCore/Debug/BudgetTracker.h
@@ -19,7 +19,7 @@ namespace AZ::Debug
class BudgetTracker
{
public:
- AZ_RTTI(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
+ AZ_TYPE_INFO(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc);
~BudgetTracker();
diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.h b/Code/Framework/AzCore/AzCore/Debug/Profiler.h
index 8af48e47f6..56103e8314 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Profiler.h
+++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.h
@@ -59,6 +59,20 @@ namespace AZStd
namespace AZ::Debug
{
+ // interface for externally defined profiler systems
+ class Profiler
+ {
+ public:
+ AZ_RTTI(Profiler, "{3E5D6329-72D1-41BA-9158-68A349D1A4D5}");
+
+ Profiler() = default;
+ virtual ~Profiler() = default;
+
+ // support for the extra macro args (e.g. format strings) will come in a later PR
+ virtual void BeginRegion(const Budget* budget, const char* eventName) = 0;
+ virtual void EndRegion(const Budget* budget) = 0;
+ };
+
class ProfileScope
{
public:
diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.inl b/Code/Framework/AzCore/AzCore/Debug/Profiler.inl
index 8ca8368ce1..74c0f553c4 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Profiler.inl
+++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.inl
@@ -6,6 +6,8 @@
*
*/
+#include
+
namespace AZ::Debug
{
template
@@ -22,9 +24,11 @@ namespace AZ::Debug
PIXBeginEvent(PIX_COLOR_INDEX(budget->Crc() & 0xff), eventName, args...);
#endif
budget->BeginProfileRegion();
-// TODO: injecting instrumentation for other profilers
-// NOTE: external profiler registration won't occur inline in a header necessarily in this manner, but the exact mechanism
-// will be introduced in a future PR
+
+ if (auto profiler = AZ::Interface::Get(); profiler)
+ {
+ profiler->BeginRegion(budget, eventName);
+ }
#endif
}
@@ -39,6 +43,10 @@ namespace AZ::Debug
#if defined(USE_PIX)
PIXEndEvent();
#endif
+ if (auto profiler = AZ::Interface::Get(); profiler)
+ {
+ profiler->EndRegion(budget);
+ }
#endif
}
diff --git a/Code/Framework/AzCore/AzCore/Debug/TraceMessagesDriller.h b/Code/Framework/AzCore/AzCore/Debug/TraceMessagesDriller.h
index 16d8f4fba3..32726931fc 100644
--- a/Code/Framework/AzCore/AzCore/Debug/TraceMessagesDriller.h
+++ b/Code/Framework/AzCore/AzCore/Debug/TraceMessagesDriller.h
@@ -28,21 +28,21 @@ namespace AZ
protected:
//////////////////////////////////////////////////////////////////////////
// Driller
- virtual const char* GroupName() const { return "SystemDrillers"; }
- virtual const char* GetName() const { return "TraceMessagesDriller"; }
- virtual const char* GetDescription() const { return "Handles all system messages like Assert, Exception, Error, Warning, Printf, etc."; }
- virtual void Start(const Param* params = NULL, int numParams = 0);
- virtual void Stop();
+ const char* GroupName() const override { return "SystemDrillers"; }
+ const char* GetName() const override { return "TraceMessagesDriller"; }
+ const char* GetDescription() const override { return "Handles all system messages like Assert, Exception, Error, Warning, Printf, etc."; }
+ void Start(const Param* params = NULL, int numParams = 0) override;
+ void Stop() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// TraceMessagesDrillerBus
/// Triggered when a AZ_Assert failed. This is terminating event! (the code will break, crash).
- virtual void OnAssert(const char* message);
- virtual void OnException(const char* message);
- virtual void OnError(const char* window, const char* message);
- virtual void OnWarning(const char* window, const char* message);
- virtual void OnPrintf(const char* window, const char* message);
+ void OnAssert(const char* message) override;
+ void OnException(const char* message) override;
+ void OnError(const char* window, const char* message) override;
+ void OnWarning(const char* window, const char* message) override;
+ void OnPrintf(const char* window, const char* message) override;
//////////////////////////////////////////////////////////////////////////
};
} // namespace Debug
diff --git a/Code/Framework/AzCore/AzCore/Driller/Stream.h b/Code/Framework/AzCore/AzCore/Driller/Stream.h
index f883984b11..5efa416ef4 100644
--- a/Code/Framework/AzCore/AzCore/Driller/Stream.h
+++ b/Code/Framework/AzCore/AzCore/Driller/Stream.h
@@ -443,7 +443,7 @@ namespace AZ
const unsigned char* GetData() const { return m_data.data(); }
unsigned int GetDataSize() const { return static_cast(m_data.size()); }
inline void Reset() { m_data.clear(); }
- virtual void WriteBinary(const void* data, unsigned int dataSize)
+ void WriteBinary(const void* data, unsigned int dataSize) override
{
m_data.insert(m_data.end(), reinterpret_cast(data), reinterpret_cast(data) + dataSize);
}
@@ -489,7 +489,7 @@ namespace AZ
}
unsigned int GetDataLeft() const { return static_cast(m_dataEnd - m_data); }
- virtual unsigned int ReadBinary(void* data, unsigned int maxDataSize)
+ unsigned int ReadBinary(void* data, unsigned int maxDataSize) override
{
AZ_Assert(m_data != nullptr, "You must call SetData function, before you can read data!");
AZ_Assert(data != nullptr && maxDataSize > 0, "We must have a valid pointer and max data size!");
@@ -523,7 +523,7 @@ namespace AZ
bool Open(const char* fileName, int mode, int platformFlags = 0);
void Close();
- virtual void WriteBinary(const void* data, unsigned int dataSize);
+ void WriteBinary(const void* data, unsigned int dataSize) override;
};
/**
@@ -540,7 +540,7 @@ namespace AZ
DrillerInputFileStream();
~DrillerInputFileStream();
bool Open(const char* fileName, int mode, int platformFlags = 0);
- virtual unsigned int ReadBinary(void* data, unsigned int maxDataSize);
+ unsigned int ReadBinary(void* data, unsigned int maxDataSize) override;
void Close();
};
diff --git a/Code/Framework/AzCore/AzCore/EBus/EBus.h b/Code/Framework/AzCore/AzCore/EBus/EBus.h
index 1bff4ff297..58754ff9b8 100644
--- a/Code/Framework/AzCore/AzCore/EBus/EBus.h
+++ b/Code/Framework/AzCore/AzCore/EBus/EBus.h
@@ -1717,6 +1717,7 @@ AZ_POP_DISABLE_WARNING
{
EBusRouterNode m_routerNode;
public:
+ virtual ~EBusNestedVersionRouter() = default;
template
void BusRouterConnect(Container& container, int order = 0);
diff --git a/Code/Framework/AzCore/AzCore/IO/CompressorZLib.h b/Code/Framework/AzCore/AzCore/IO/CompressorZLib.h
index abd21e1450..dd1fb226c3 100644
--- a/Code/Framework/AzCore/AzCore/IO/CompressorZLib.h
+++ b/Code/Framework/AzCore/AzCore/IO/CompressorZLib.h
@@ -98,21 +98,21 @@ namespace AZ
/// Return compressor type id.
static AZ::u32 TypeId();
- virtual AZ::u32 GetTypeId() const { return TypeId(); }
+ AZ::u32 GetTypeId() const override { return TypeId(); }
/// Called when we open a stream to Read for the first time. Data contains the first. dataSize <= m_maxHeaderSize.
- virtual bool ReadHeaderAndData(CompressorStream* stream, AZ::u8* data, unsigned int dataSize);
+ bool ReadHeaderAndData(CompressorStream* stream, AZ::u8* data, unsigned int dataSize) override;
/// Called when we are about to start writing to a compressed stream.
- virtual bool WriteHeaderAndData(CompressorStream* stream);
+ bool WriteHeaderAndData(CompressorStream* stream) override;
/// Forwarded function from the Device when we from a compressed stream.
- virtual SizeType Read(CompressorStream* stream, SizeType byteSize, SizeType offset, void* buffer);
+ SizeType Read(CompressorStream* stream, SizeType byteSize, SizeType offset, void* buffer) override;
/// Forwarded function from the Device when we write to a compressed stream.
- virtual SizeType Write(CompressorStream* stream, SizeType byteSize, const void* data, SizeType offset = SizeType(-1));
+ SizeType Write(CompressorStream* stream, SizeType byteSize, const void* data, SizeType offset = SizeType(-1)) override;
/// Write a seek point.
- virtual bool WriteSeekPoint(CompressorStream* stream);
+ bool WriteSeekPoint(CompressorStream* stream) override;
/// Set auto seek point even dataSize bytes.
- virtual bool StartCompressor(CompressorStream* stream, int compressionLevel, SizeType autoSeekDataSize);
+ bool StartCompressor(CompressorStream* stream, int compressionLevel, SizeType autoSeekDataSize) override;
/// Called just before we close the stream. All compression data will be flushed and finalized. (You can't add data afterwards).
- virtual bool Close(CompressorStream* stream);
+ bool Close(CompressorStream* stream) override;
protected:
diff --git a/Code/Framework/AzCore/AzCore/IO/FileReader.cpp b/Code/Framework/AzCore/AzCore/IO/FileReader.cpp
new file mode 100644
index 0000000000..94118cdfe4
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/IO/FileReader.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+
+namespace AZ::IO
+{
+ FileReader::FileReader() = default;
+
+ FileReader::FileReader(AZ::IO::FileIOBase* fileIoBase, const char* filePath)
+ {
+ Open(fileIoBase, filePath);
+ }
+
+ FileReader::~FileReader()
+ {
+ Close();
+ }
+
+ FileReader::FileReader(FileReader&& other)
+ {
+ AZStd::swap(m_file, other.m_file);
+ AZStd::swap(m_fileIoBase, other.m_fileIoBase);
+ }
+
+ FileReader& FileReader::operator=(FileReader&& other)
+ {
+ // Close the current file and take over other file
+ Close();
+ m_file = AZStd::move(other.m_file);
+ m_fileIoBase = AZStd::move(other.m_fileIoBase);
+ other.m_file = AZStd::monostate{};
+ other.m_fileIoBase = {};
+
+ return *this;
+ }
+
+ bool FileReader::Open(AZ::IO::FileIOBase* fileIoBase, const char* filePath)
+ {
+ // Close file if the FileReader has an instance open
+ Close();
+
+ if (fileIoBase != nullptr)
+ {
+ AZ::IO::HandleType fileHandle;
+ if (fileIoBase->Open(filePath, IO::OpenMode::ModeRead, fileHandle))
+ {
+ m_file = fileHandle;
+ m_fileIoBase = fileIoBase;
+ return true;
+ }
+ }
+ else
+ {
+ AZ::IO::SystemFile file;
+ if (file.Open(filePath, IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY))
+ {
+ m_file = AZStd::move(file);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool FileReader::IsOpen() const
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ return *fileHandle != AZ::IO::InvalidHandle;
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ return systemFile->IsOpen();
+ }
+
+ return false;
+ }
+
+ void FileReader::Close()
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ if (AZ::IO::FileIOBase* fileIo = m_fileIoBase; fileIo != nullptr)
+ {
+ fileIo->Close(*fileHandle);
+ }
+ }
+
+ m_file = AZStd::monostate{};
+ m_fileIoBase = {};
+ }
+
+ auto FileReader::Length() const -> SizeType
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ if (SizeType fileSize{}; m_fileIoBase->Size(*fileHandle, fileSize))
+ {
+ return fileSize;
+ }
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ return systemFile->Length();
+ }
+
+ return 0;
+ }
+
+ auto FileReader::Read(SizeType byteSize, void* buffer) -> SizeType
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ if (SizeType bytesRead{}; m_fileIoBase->Read(*fileHandle, buffer, byteSize, false, &bytesRead))
+ {
+ return bytesRead;
+ }
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ return systemFile->Read(byteSize, buffer);
+ }
+
+ return 0;
+ }
+
+ auto FileReader::Tell() const -> SizeType
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ if (SizeType fileOffset{}; m_fileIoBase->Tell(*fileHandle, fileOffset))
+ {
+ return fileOffset;
+ }
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ return systemFile->Tell();
+ }
+
+ return 0;
+ }
+
+ bool FileReader::Seek(AZ::s64 offset, SeekType type)
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ return m_fileIoBase->Seek(*fileHandle, offset, type);
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ systemFile->Seek(offset, static_cast(type));
+ return true;
+ }
+
+ return false;
+ }
+
+ bool FileReader::Eof() const
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ return m_fileIoBase->Eof(*fileHandle);
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ return systemFile->Eof();
+ }
+
+ return false;
+ }
+
+ bool FileReader::GetFilePath(AZ::IO::FixedMaxPath& filePath) const
+ {
+ if (auto fileHandle = AZStd::get_if(&m_file); fileHandle != nullptr)
+ {
+ AZ::IO::FixedMaxPathString& pathStringRef = filePath.Native();
+ if (m_fileIoBase->GetFilename(*fileHandle, pathStringRef.data(), pathStringRef.capacity()))
+ {
+ pathStringRef.resize_no_construct(AZStd::char_traits::length(pathStringRef.data()));
+ return true;
+ }
+ }
+ else if (auto systemFile = AZStd::get_if(&m_file); systemFile != nullptr)
+ {
+ filePath = systemFile->Name();
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/Code/Framework/AzCore/AzCore/IO/FileReader.h b/Code/Framework/AzCore/AzCore/IO/FileReader.h
new file mode 100644
index 0000000000..4fdb18b2b2
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/IO/FileReader.h
@@ -0,0 +1,92 @@
+/*
+ * 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
+#include
+
+namespace AZ::IO
+{
+ class FileIOBase;
+ enum class SeekType : AZ::u32;
+
+ //! Structure which encapsulates delegates File Read operations
+ //! to either the FileIOBase or SystemFile classes based if a FileIOBase* instance has been supplied
+ //! to the FileSystemReader class
+ //! the SettingsRegistry option to use FileIO
+ class FileReader
+ {
+ using HandleType = AZ::u32;
+ using FileHandleType = AZStd::variant;
+ public:
+ using SizeType = AZ::u64;
+
+ //! Creates FileReader instance in the default state with no file opend
+ FileReader();
+ ~FileReader();
+
+ //! Creates a new FileReader instance and attempts to open the file at the supplied path
+ //! Uses the FileIOBase instance if supplied
+ //! @param fileIOBase pointer to fileIOBase instance
+ //! @param null-terminated filePath to open
+ FileReader(AZ::IO::FileIOBase* fileIoBase, const char* filePath);
+
+ //! Takes ownership of the supplied FileReader handle
+ FileReader(FileReader&& other);
+
+ //! Moves ownership of FileReader handle to this instance
+ FileReader& operator=(FileReader&& other);
+
+ //! Opens a File using the FileIOBase instance if non-nullptr
+ //! Otherwise fall back to use SystemFile
+ //! @param fileIOBase pointer to fileIOBase instance
+ //! @param null-terminated filePath to open
+ //! @return true if the File is opened successfully
+ bool Open(AZ::IO::FileIOBase* fileIoBase, const char* filePath);
+
+ //! Returns true if a file is currently open
+ //! @return true if the file is open
+ bool IsOpen() const;
+
+ //! Closes the File
+ void Close();
+
+ //! Retrieve the length of the OpenFile
+ SizeType Length() const;
+
+ //! Attempts to read up to byte size bytes into the supplied buffer
+ //! @param byteSize - Maximum number of bytes to read
+ //! @param buffer - Buffer to read bytes into
+ //! @returns the number of bytes read if the file is open, otherwise 0
+ SizeType Read(SizeType byteSize, void* buffer);
+
+ //! Returns the current file offset
+ //! @returns file offset if the file is open, otherwise 0
+ SizeType Tell() const;
+
+ //! Seeks within the open file to the offset supplied
+ //! @param offset File offset to seek to
+ //! @param type parameter to indicate the reference point to start the seek from
+ //! @returns true if the file is open and the seek succeeded
+ bool Seek(AZ::s64 offset, SeekType type);
+
+ //! Returns true if the file is open and in the EOF state
+ bool Eof() const;
+
+ //! Store the file path of the open file into the output file path parameter
+ //! The filePath reference is left unmodified, if the path was not stored
+ //! @return true if the filePath was stored
+ bool GetFilePath(AZ::IO::FixedMaxPath& filePath) const;
+
+ private:
+
+ FileHandleType m_file;
+ AZ::IO::FileIOBase* m_fileIoBase{};
+ };
+}
diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp
index 5bff79b422..651abb89fe 100644
--- a/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp
+++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.cpp
@@ -160,12 +160,12 @@ void SystemFile::Seek(SeekSizeType offset, SeekMode mode)
Platform::Seek(m_handle, this, offset, mode);
}
-SystemFile::SizeType SystemFile::Tell()
+SystemFile::SizeType SystemFile::Tell() const
{
return Platform::Tell(m_handle, this);
}
-bool SystemFile::Eof()
+bool SystemFile::Eof() const
{
return Platform::Eof(m_handle, this);
}
diff --git a/Code/Framework/AzCore/AzCore/IO/SystemFile.h b/Code/Framework/AzCore/AzCore/IO/SystemFile.h
index 8a5b2b2521..551ce89ce7 100644
--- a/Code/Framework/AzCore/AzCore/IO/SystemFile.h
+++ b/Code/Framework/AzCore/AzCore/IO/SystemFile.h
@@ -72,9 +72,9 @@ namespace AZ
/// Seek in current file.
void Seek(SeekSizeType offset, SeekMode mode);
/// Get the cursor position in the current file.
- SizeType Tell();
+ SizeType Tell() const;
/// Is the cursor at the end of the file?
- bool Eof();
+ bool Eof() const;
/// Get the time the file was last modified.
AZ::u64 ModificationTime();
/// Read data from a file synchronous. Return number of bytes actually read in the buffer.
diff --git a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobNotify.h b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobNotify.h
index 9b6a39af4f..1c15b7105e 100644
--- a/Code/Framework/AzCore/AzCore/Jobs/Internal/JobNotify.h
+++ b/Code/Framework/AzCore/AzCore/Jobs/Internal/JobNotify.h
@@ -31,7 +31,7 @@ namespace AZ
{
}
protected:
- virtual void Process()
+ void Process() override
{
m_notifyFlag->store(true, AZStd::memory_order_release);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/InterpolationSample.h b/Code/Framework/AzCore/AzCore/Math/InterpolationSample.h
index 12b18f86b8..942f02727e 100644
--- a/Code/Framework/AzCore/AzCore/Math/InterpolationSample.h
+++ b/Code/Framework/AzCore/AzCore/Math/InterpolationSample.h
@@ -77,7 +77,7 @@ namespace AZ
: public Sample
{
public:
- Vector3 GetInterpolatedValue(TimeType time) override final
+ Vector3 GetInterpolatedValue(TimeType time) final
{
Vector3 interpolatedValue = m_previousValue;
if (m_targetTimestamp != 0)
@@ -108,7 +108,7 @@ namespace AZ
: public Sample
{
public:
- Quaternion GetInterpolatedValue(TimeType time) override final
+ Quaternion GetInterpolatedValue(TimeType time) final
{
Quaternion interpolatedValue = m_previousValue;
if (m_targetTimestamp != 0)
@@ -144,7 +144,7 @@ namespace AZ
: public Sample
{
public:
- Vector3 GetInterpolatedValue(TimeType /*time*/) override final
+ Vector3 GetInterpolatedValue(TimeType /*time*/) final
{
return GetTargetValue();
}
@@ -155,7 +155,7 @@ namespace AZ
: public Sample
{
public:
- Quaternion GetInterpolatedValue(TimeType /*time*/) override final
+ Quaternion GetInterpolatedValue(TimeType /*time*/) final
{
return GetTargetValue();
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Transform.cpp b/Code/Framework/AzCore/AzCore/Math/Transform.cpp
index 5cb09fe9a8..1701820bae 100644
--- a/Code/Framework/AzCore/AzCore/Math/Transform.cpp
+++ b/Code/Framework/AzCore/AzCore/Math/Transform.cpp
@@ -353,6 +353,7 @@ namespace AZ
Method("CreateFromMatrix3x3AndTranslation", &Transform::CreateFromMatrix3x3AndTranslation)->
Method("CreateUniformScale", &Transform::CreateUniformScale)->
Method("CreateTranslation", &Transform::CreateTranslation)->
+ Method("CreateLookAt", &Transform::CreateLookAt)->
Method("ConstructFromValuesNumeric", &Internal::ConstructTransformFromValues);
}
}
diff --git a/Code/Framework/AzCore/AzCore/Memory/HeapSchema.h b/Code/Framework/AzCore/AzCore/Memory/HeapSchema.h
index f6c6f98315..f72ae31057 100644
--- a/Code/Framework/AzCore/AzCore/Memory/HeapSchema.h
+++ b/Code/Framework/AzCore/AzCore/Memory/HeapSchema.h
@@ -48,18 +48,18 @@ namespace AZ
HeapSchema(const Descriptor& desc);
virtual ~HeapSchema();
- virtual pointer_type Allocate(size_type byteSize, size_type alignment, int flags, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0);
- virtual void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0);
- virtual pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) { (void)ptr; (void)newSize; (void)newAlignment; return NULL; }
- virtual size_type Resize(pointer_type ptr, size_type newSize) { (void)ptr; (void)newSize; return 0; }
- virtual size_type AllocationSize(pointer_type ptr);
+ pointer_type Allocate(size_type byteSize, size_type alignment, int flags, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override;
+ void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override;
+ pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override { (void)ptr; (void)newSize; (void)newAlignment; return NULL; }
+ size_type Resize(pointer_type ptr, size_type newSize) override { (void)ptr; (void)newSize; return 0; }
+ size_type AllocationSize(pointer_type ptr) override;
- virtual size_type NumAllocatedBytes() const { return m_used; }
- virtual size_type Capacity() const { return m_capacity; }
- virtual size_type GetMaxAllocationSize() const;
- size_type GetMaxContiguousAllocationSize() const override;
- virtual IAllocatorAllocate* GetSubAllocator() { return m_subAllocator; }
- virtual void GarbageCollect() {}
+ size_type NumAllocatedBytes() const override { return m_used; }
+ size_type Capacity() const override { return m_capacity; }
+ size_type GetMaxAllocationSize() const override;
+ size_type GetMaxContiguousAllocationSize() const override;
+ IAllocatorAllocate* GetSubAllocator() override { return m_subAllocator; }
+ void GarbageCollect() override {}
private:
AZ_FORCE_INLINE size_type ChunckSize(pointer_type ptr);
diff --git a/Code/Framework/AzCore/AzCore/Memory/HphaSchema.h b/Code/Framework/AzCore/AzCore/Memory/HphaSchema.h
index 0f84ca1e68..5ee0205196 100644
--- a/Code/Framework/AzCore/AzCore/Memory/HphaSchema.h
+++ b/Code/Framework/AzCore/AzCore/Memory/HphaSchema.h
@@ -56,22 +56,22 @@ namespace AZ
HphaSchema(const Descriptor& desc);
virtual ~HphaSchema();
- virtual pointer_type Allocate(size_type byteSize, size_type alignment, int flags = 0, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0);
- virtual void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0);
- virtual pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment);
+ pointer_type Allocate(size_type byteSize, size_type alignment, int flags = 0, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override;
+ void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override;
+ pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override;
/// Resizes allocated memory block to the size possible and returns that size.
- virtual size_type Resize(pointer_type ptr, size_type newSize);
- virtual size_type AllocationSize(pointer_type ptr);
+ size_type Resize(pointer_type ptr, size_type newSize) override;
+ size_type AllocationSize(pointer_type ptr) override;
- virtual size_type NumAllocatedBytes() const;
- virtual size_type Capacity() const;
- virtual size_type GetMaxAllocationSize() const;
- size_type GetMaxContiguousAllocationSize() const override;
- virtual size_type GetUnAllocatedMemory(bool isPrint = false) const;
- virtual IAllocatorAllocate* GetSubAllocator() { return m_desc.m_subAllocator; }
+ size_type NumAllocatedBytes() const override;
+ size_type Capacity() const override;
+ size_type GetMaxAllocationSize() const override;
+ size_type GetMaxContiguousAllocationSize() const override;
+ size_type GetUnAllocatedMemory(bool isPrint = false) const override;
+ IAllocatorAllocate* GetSubAllocator() override { return m_desc.m_subAllocator; }
/// Return unused memory to the OS (if we don't use fixed block). Don't call this unless you really need free memory, it is slow.
- virtual void GarbageCollect();
+ void GarbageCollect() override;
private:
// [LY-84974][sconel@][2018-08-10] SliceStrike integration up to CL 671758
diff --git a/Code/Framework/AzCore/AzCore/Memory/MallocSchema.h b/Code/Framework/AzCore/AzCore/Memory/MallocSchema.h
index cbf928e189..7a8c4a0366 100644
--- a/Code/Framework/AzCore/AzCore/Memory/MallocSchema.h
+++ b/Code/Framework/AzCore/AzCore/Memory/MallocSchema.h
@@ -41,18 +41,18 @@ namespace AZ
//---------------------------------------------------------------------
// IAllocatorAllocate
//---------------------------------------------------------------------
- virtual pointer_type Allocate(size_type byteSize, size_type alignment, int flags, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override;
- virtual void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override;
- virtual pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override;
- virtual size_type Resize(pointer_type ptr, size_type newSize) override;
- virtual size_type AllocationSize(pointer_type ptr) override;
+ pointer_type Allocate(size_type byteSize, size_type alignment, int flags, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override;
+ void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override;
+ pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override;
+ size_type Resize(pointer_type ptr, size_type newSize) override;
+ size_type AllocationSize(pointer_type ptr) override;
- virtual size_type NumAllocatedBytes() const override;
- virtual size_type Capacity() const override;
- virtual size_type GetMaxAllocationSize() const override;
- virtual size_type GetMaxContiguousAllocationSize() const override;
- virtual IAllocatorAllocate* GetSubAllocator() override;
- virtual void GarbageCollect() override;
+ size_type NumAllocatedBytes() const override;
+ size_type Capacity() const override;
+ size_type GetMaxAllocationSize() const override;
+ size_type GetMaxContiguousAllocationSize() const override;
+ IAllocatorAllocate* GetSubAllocator() override;
+ void GarbageCollect() override;
private:
typedef void* (*MallocFn)(size_t);
diff --git a/Code/Framework/AzCore/AzCore/Memory/Memory.h b/Code/Framework/AzCore/AzCore/Memory/Memory.h
index d09003f3f0..2e08ec1b15 100644
--- a/Code/Framework/AzCore/AzCore/Memory/Memory.h
+++ b/Code/Framework/AzCore/AzCore/Memory/Memory.h
@@ -849,7 +849,7 @@ namespace AZ
return AZ::AllocatorInstance::Get().GetUnAllocatedMemory(isPrint);
}
- virtual IAllocatorAllocate* GetSubAllocator() override
+ IAllocatorAllocate* GetSubAllocator() override
{
return AZ::AllocatorInstance::Get().GetSubAllocator();
}
diff --git a/Code/Framework/AzCore/AzCore/Memory/MemoryDriller.h b/Code/Framework/AzCore/AzCore/Memory/MemoryDriller.h
index 94c364c719..9bcbc85217 100644
--- a/Code/Framework/AzCore/AzCore/Memory/MemoryDriller.h
+++ b/Code/Framework/AzCore/AzCore/Memory/MemoryDriller.h
@@ -38,24 +38,24 @@ namespace AZ
protected:
//////////////////////////////////////////////////////////////////////////
// Driller
- virtual const char* GroupName() const { return "SystemDrillers"; }
- virtual const char* GetName() const { return "MemoryDriller"; }
- virtual const char* GetDescription() const { return "Reports all allocators and memory allocations."; }
- virtual void Start(const Param* params = NULL, int numParams = 0);
- virtual void Stop();
+ const char* GroupName() const override { return "SystemDrillers"; }
+ const char* GetName() const override { return "MemoryDriller"; }
+ const char* GetDescription() const override { return "Reports all allocators and memory allocations."; }
+ void Start(const Param* params = NULL, int numParams = 0) override;
+ void Stop() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// MemoryDrillerBus
- virtual void RegisterAllocator(IAllocator* allocator);
- virtual void UnregisterAllocator(IAllocator* allocator);
+ void RegisterAllocator(IAllocator* allocator) override;
+ void UnregisterAllocator(IAllocator* allocator) override;
- virtual void RegisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount);
- virtual void UnregisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, AllocationInfo* info);
- virtual void ReallocateAllocation(IAllocator* allocator, void* prevAddress, void* newAddress, size_t newByteSize, size_t newAlignment);
- virtual void ResizeAllocation(IAllocator* allocator, void* address, size_t newSize);
+ void RegisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount) override;
+ void UnregisterAllocation(IAllocator* allocator, void* address, size_t byteSize, size_t alignment, AllocationInfo* info) override;
+ void ReallocateAllocation(IAllocator* allocator, void* prevAddress, void* newAddress, size_t newByteSize, size_t newAlignment) override;
+ void ResizeAllocation(IAllocator* allocator, void* address, size_t newSize) override;
- virtual void DumpAllAllocations();
+ void DumpAllAllocations() override;
//////////////////////////////////////////////////////////////////////////
void RegisterAllocatorOutput(IAllocator* allocator);
diff --git a/Code/Framework/AzCore/AzCore/Memory/OverrunDetectionAllocator.h b/Code/Framework/AzCore/AzCore/Memory/OverrunDetectionAllocator.h
index 3dffdfad56..9895a5f84f 100644
--- a/Code/Framework/AzCore/AzCore/Memory/OverrunDetectionAllocator.h
+++ b/Code/Framework/AzCore/AzCore/Memory/OverrunDetectionAllocator.h
@@ -77,18 +77,18 @@ namespace AZ
//---------------------------------------------------------------------
// IAllocatorAllocate
//---------------------------------------------------------------------
- virtual pointer_type Allocate(size_type byteSize, size_type alignment, int flags, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override;
- virtual void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override;
- virtual pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override;
- virtual size_type Resize(pointer_type ptr, size_type newSize) override;
- virtual size_type AllocationSize(pointer_type ptr) override;
+ pointer_type Allocate(size_type byteSize, size_type alignment, int flags, const char* name = 0, const char* fileName = 0, int lineNum = 0, unsigned int suppressStackRecord = 0) override;
+ void DeAllocate(pointer_type ptr, size_type byteSize = 0, size_type alignment = 0) override;
+ pointer_type ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment) override;
+ size_type Resize(pointer_type ptr, size_type newSize) override;
+ size_type AllocationSize(pointer_type ptr) override;
- virtual size_type NumAllocatedBytes() const override;
- virtual size_type Capacity() const override;
- virtual size_type GetMaxAllocationSize() const override;
+ size_type NumAllocatedBytes() const override;
+ size_type Capacity() const override;
+ size_type GetMaxAllocationSize() const override;
size_type GetMaxContiguousAllocationSize() const override;
- virtual IAllocatorAllocate* GetSubAllocator() override;
- virtual void GarbageCollect() override;
+ IAllocatorAllocate* GetSubAllocator() override;
+ void GarbageCollect() override;
private:
OverrunDetectionSchemaImpl* m_impl;
diff --git a/Code/Framework/AzCore/AzCore/Module/Module.h b/Code/Framework/AzCore/AzCore/Module/Module.h
index a4843f002c..3809bd1bb4 100644
--- a/Code/Framework/AzCore/AzCore/Module/Module.h
+++ b/Code/Framework/AzCore/AzCore/Module/Module.h
@@ -62,7 +62,7 @@ namespace AZ
* DO NOT OVERRIDE. This method will return in the future, but at this point things reflected here are not unreflected for all ReflectContexts (Serialize, Editor, Network, Script, etc.)
* Place all calls to non-component reflect functions inside of a component reflect function to ensure that your types are unreflected.
*/
- virtual void Reflect(AZ::ReflectContext*) final { }
+ void Reflect(AZ::ReflectContext*) {}
/**
* Override to require specific components on the system entity.
diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h
index b436f5adab..0a1af21213 100644
--- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h
+++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorContext.h
@@ -594,8 +594,8 @@ namespace AZ
void SetArgumentName(size_t index, const AZStd::string& name) override;
const AZStd::string* GetArgumentToolTip(size_t index) const override;
void SetArgumentToolTip(size_t index, const AZStd::string& name) override;
- virtual void SetDefaultValue(size_t index, BehaviorDefaultValuePtr defaultValue) override;
- virtual BehaviorDefaultValuePtr GetDefaultValue(size_t index) const override;
+ void SetDefaultValue(size_t index, BehaviorDefaultValuePtr defaultValue) override;
+ BehaviorDefaultValuePtr GetDefaultValue(size_t index) const override;
const BehaviorParameter* GetResult() const override;
void OverrideParameterTraits(size_t index, AZ::u32 addTraits, AZ::u32 removeTraits) override;
diff --git a/Code/Framework/AzCore/AzCore/RTTI/RTTI.h b/Code/Framework/AzCore/AzCore/RTTI/RTTI.h
index fa081a9497..acf6f64f77 100644
--- a/Code/Framework/AzCore/AzCore/RTTI/RTTI.h
+++ b/Code/Framework/AzCore/AzCore/RTTI/RTTI.h
@@ -5,8 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#ifndef AZCORE_RTTI_H
-#define AZCORE_RTTI_H
+
+#pragma once
#include
#include
@@ -44,21 +44,9 @@ namespace AZ
/// RTTI typeId
typedef void (* RTTI_EnumCallback)(const AZ::TypeId& /*typeId*/, void* /*userData*/);
- // Disabling missing override warning because we intentionally want to allow for declaring RTTI base classes that don't impelment RTTI.
-#if defined(AZ_COMPILER_CLANG)
-# define AZ_PUSH_DISABLE_OVERRIDE_WARNING \
- _Pragma("clang diagnostic push") \
- _Pragma("clang diagnostic ignored \"-Winconsistent-missing-override\"")
-# define AZ_POP_DISABLE_OVERRIDE_WARNING \
- _Pragma("clang diagnostic pop")
-#else
-# define AZ_PUSH_DISABLE_OVERRIDE_WARNING
-# define AZ_POP_DISABLE_OVERRIDE_WARNING
-#endif
-
// We require AZ_TYPE_INFO to be declared
#define AZ_RTTI_COMMON() \
- AZ_PUSH_DISABLE_OVERRIDE_WARNING \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
void RTTI_Enable(); \
virtual inline const AZ::TypeId& RTTI_GetType() const { return RTTI_Type(); } \
virtual inline const char* RTTI_GetTypeName() const { return RTTI_TypeName(); } \
@@ -66,7 +54,7 @@ namespace AZ
virtual void RTTI_EnumTypes(AZ::RTTI_EnumCallback cb, void* userData) { RTTI_EnumHierarchy(cb, userData); } \
static inline const AZ::TypeId& RTTI_Type() { return TYPEINFO_Uuid(); } \
static inline const char* RTTI_TypeName() { return TYPEINFO_Name(); } \
- AZ_POP_DISABLE_OVERRIDE_WARNING
+ AZ_POP_DISABLE_WARNING
//#define AZ_RTTI_1(_1) static_assert(false,"You must provide a valid classUuid!")
@@ -74,8 +62,10 @@ namespace AZ
#define AZ_RTTI_1() AZ_RTTI_COMMON() \
static bool RTTI_IsContainType(const AZ::TypeId& id) { return id == RTTI_Type(); } \
static void RTTI_EnumHierarchy(AZ::RTTI_EnumCallback cb, void* userData) { cb(RTTI_Type(), userData); } \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
virtual inline const void* RTTI_AddressOf(const AZ::TypeId& id) const { return (id == RTTI_Type()) ? this : nullptr; } \
- virtual inline void* RTTI_AddressOf(const AZ::TypeId& id) { return (id == RTTI_Type()) ? this : nullptr; }
+ virtual inline void* RTTI_AddressOf(const AZ::TypeId& id) { return (id == RTTI_Type()) ? this : nullptr; } \
+ AZ_POP_DISABLE_WARNING
/// AZ_RTTI(BaseClass)
#define AZ_RTTI_2(_1) AZ_RTTI_COMMON() \
@@ -85,14 +75,14 @@ namespace AZ
static void RTTI_EnumHierarchy(AZ::RTTI_EnumCallback cb, void* userData) { \
cb(RTTI_Type(), userData); \
AZ::Internal::RttiCaller<_1>::RTTI_EnumHierarchy(cb, userData); } \
- AZ_PUSH_DISABLE_OVERRIDE_WARNING \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
virtual inline const void* RTTI_AddressOf(const AZ::TypeId& id) const { \
if (id == RTTI_Type()) { return this; } \
return AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); } \
virtual inline void* RTTI_AddressOf(const AZ::TypeId& id) { \
if (id == RTTI_Type()) { return this; } \
return AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); } \
- AZ_POP_DISABLE_OVERRIDE_WARNING
+ AZ_POP_DISABLE_WARNING
/// AZ_RTTI(BaseClass1,BaseClass2)
#define AZ_RTTI_3(_1, _2) AZ_RTTI_COMMON() \
@@ -104,7 +94,7 @@ namespace AZ
cb(RTTI_Type(), userData); \
AZ::Internal::RttiCaller<_1>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_2>::RTTI_EnumHierarchy(cb, userData); } \
- AZ_PUSH_DISABLE_OVERRIDE_WARNING \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
virtual inline const void* RTTI_AddressOf(const AZ::TypeId& id) const { \
if (id == RTTI_Type()) { return this; } \
const void* r = AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); if (r) { return r; } \
@@ -113,7 +103,7 @@ namespace AZ
if (id == RTTI_Type()) { return this; } \
void* r = AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); if (r) { return r; } \
return AZ::Internal::RttiCaller<_2>::RTTI_AddressOf(this, id); } \
- AZ_POP_DISABLE_OVERRIDE_WARNING
+ AZ_POP_DISABLE_WARNING
/// AZ_RTTI(BaseClass1,BaseClass2,BaseClass3)
#define AZ_RTTI_4(_1, _2, _3) AZ_RTTI_COMMON() \
@@ -127,7 +117,7 @@ namespace AZ
AZ::Internal::RttiCaller<_1>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_2>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_3>::RTTI_EnumHierarchy(cb, userData); } \
- AZ_PUSH_DISABLE_OVERRIDE_WARNING \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
virtual inline const void* RTTI_AddressOf(const AZ::TypeId& id) const { \
if (id == RTTI_Type()) { return this; } \
const void* r = AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); if (r) { return r; } \
@@ -138,7 +128,7 @@ namespace AZ
void* r = AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); if (r) { return r; } \
r = AZ::Internal::RttiCaller<_2>::RTTI_AddressOf(this, id); if (r) { return r; } \
return AZ::Internal::RttiCaller<_3>::RTTI_AddressOf(this, id); } \
- AZ_POP_DISABLE_OVERRIDE_WARNING
+ AZ_POP_DISABLE_WARNING
/// AZ_RTTI(BaseClass1,BaseClass2,BaseClass3,BaseClass4)
#define AZ_RTTI_5(_1, _2, _3, _4) AZ_RTTI_COMMON() \
@@ -154,7 +144,7 @@ namespace AZ
AZ::Internal::RttiCaller<_2>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_3>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_4>::RTTI_EnumHierarchy(cb, userData); } \
- AZ_PUSH_DISABLE_OVERRIDE_WARNING \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
virtual inline const void* RTTI_AddressOf(const AZ::TypeId& id) const { \
if (id == RTTI_Type()) { return this; } \
const void* r = AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); if (r) { return r; } \
@@ -167,7 +157,7 @@ namespace AZ
r = AZ::Internal::RttiCaller<_2>::RTTI_AddressOf(this, id); if (r) { return r; } \
r = AZ::Internal::RttiCaller<_3>::RTTI_AddressOf(this, id); if (r) { return r; } \
return AZ::Internal::RttiCaller<_4>::RTTI_AddressOf(this, id); } \
- AZ_POP_DISABLE_OVERRIDE_WARNING
+ AZ_POP_DISABLE_WARNING
/// AZ_RTTI(BaseClass1,BaseClass2,BaseClass3,BaseClass4,BaseClass5)
#define AZ_RTTI_6(_1, _2, _3, _4, _5) AZ_RTTI_COMMON() \
@@ -185,7 +175,7 @@ namespace AZ
AZ::Internal::RttiCaller<_3>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_4>::RTTI_EnumHierarchy(cb, userData); \
AZ::Internal::RttiCaller<_5>::RTTI_EnumHierarchy(cb, userData); } \
- AZ_PUSH_DISABLE_OVERRIDE_WARNING \
+ AZ_PUSH_DISABLE_WARNING(26433, "-Winconsistent-missing-override") \
virtual inline const void* RTTI_AddressOf(const AZ::TypeId& id) const { \
if (id == RTTI_Type()) { return this; } \
const void* r = AZ::Internal::RttiCaller<_1>::RTTI_AddressOf(this, id); if (r) { return r; } \
@@ -200,7 +190,7 @@ namespace AZ
r = AZ::Internal::RttiCaller<_3>::RTTI_AddressOf(this, id); if (r) { return r; } \
r = AZ::Internal::RttiCaller<_4>::RTTI_AddressOf(this, id); if (r) { return r; } \
return AZ::Internal::RttiCaller<_5>::RTTI_AddressOf(this, id); } \
- AZ_POP_DISABLE_OVERRIDE_WARNING
+ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MACRO specialization to allow optional parameters for template version of AZ_RTTI
@@ -951,10 +941,7 @@ namespace AZ
{
return AZStd::shared_ptr(ptr, castPtr);
}
- else
- {
- return AZStd::shared_ptr();
- }
+ return AZStd::shared_ptr();
}
// RttiCast specialization for intrusive_ptr.
@@ -1077,7 +1064,6 @@ namespace AZ
{
return AZ::Internal::RttiIsTypeOfIdHelper::Check(id, data, typename HasAZRtti>::kind_type());
}
+
} // namespace AZ
-#endif // AZCORE_RTTI_H
-#pragma once
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.h b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.h
index c46ba32209..a691bb1bcb 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.h
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.h
@@ -19,8 +19,8 @@ namespace AZ
public:
AZ_COMPONENT(JsonSystemComponent, "{3C2C7234-9512-4E24-86F0-C40865D7EECE}", Component);
- void Activate();
- void Deactivate();
+ void Activate() override;
+ void Deactivate() override;
static void Reflect(ReflectContext* reflectContext);
};
diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.h
index e0d2635fc3..937c8389ff 100644
--- a/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.h
+++ b/Code/Framework/AzCore/AzCore/Serialization/Json/MapSerializer.h
@@ -46,7 +46,8 @@ namespace AZ
public:
AZ_RTTI(JsonUnorderedMapSerializer, "{EF4478D3-1820-4FDB-A7B7-C9711EB41602}", JsonMapSerializer);
AZ_CLASS_ALLOCATOR_DECL;
-
+
+ using JsonMapSerializer::Store;
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
const Uuid& valueTypeId, JsonSerializerContext& context) override;
};
@@ -63,6 +64,7 @@ namespace AZ
const SerializeContext::ClassElement* keyElement, const SerializeContext::ClassElement* valueElement,
const rapidjson::Value& key, const rapidjson::Value& value, JsonDeserializerContext& context) override;
+ using JsonMapSerializer::Store;
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
const Uuid& valueTypeId, JsonSerializerContext& context) override;
};
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
index 106e232904..3dc1be87c5 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h
@@ -370,6 +370,11 @@ namespace AZ
//! @param applyPatchSettings The ApplyPatchSettings which are using during JSON Merging
virtual void SetApplyPatchSettings(const AZ::JsonApplyPatchSettings& applyPatchSettings) = 0;
virtual void GetApplyPatchSettings(AZ::JsonApplyPatchSettings& applyPatchSettings) = 0;
+
+ //! Stores option to indicate whether the FileIOBase instance should be used for file operations
+ //! @param useFileIo If true the FileIOBase instance will attempted to be used for FileIOBase
+ //! operations before falling back to use SystemFile
+ virtual void SetUseFileIO(bool useFileIo) = 0;
};
inline SettingsRegistryInterface::Visitor::~Visitor() = default;
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp
index 6864dcd1c8..92f546815e 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.cpp
@@ -9,11 +9,15 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
@@ -131,6 +135,12 @@ namespace AZ
pointer.Create(m_settings, m_settings.GetAllocator()).SetArray();
}
+ SettingsRegistryImpl::SettingsRegistryImpl(bool useFileIo)
+ : SettingsRegistryImpl()
+ {
+ m_useFileIo = useFileIo;
+ }
+
void SettingsRegistryImpl::SetContext(SerializeContext* context)
{
AZStd::scoped_lock lock(m_settingMutex);
@@ -723,15 +733,10 @@ namespace AZ
RegistryFileList fileList;
scratchBuffer->clear();
- AZ::IO::FixedMaxPathString folderPath{ path };
- constexpr AZStd::string_view pathSeparators{ AZ_CORRECT_AND_WRONG_DATABASE_SEPARATOR };
- if (pathSeparators.find_first_of(folderPath.back()) == AZStd::string_view::npos)
- {
- folderPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
- }
+ AZ::IO::FixedMaxPath folderPath{ path };
- const size_t platformKeyOffset = folderPath.size();
- folderPath.push_back('*');
+ const size_t platformKeyOffset = folderPath.Native().size();
+ folderPath /= '*';
Value specialzationArray(kArrayType);
size_t specializationCount = specializations.GetCount();
@@ -741,47 +746,13 @@ namespace AZ
specialzationArray.PushBack(Value(name.data(), aznumeric_caster(name.length()), m_settings.GetAllocator()), m_settings.GetAllocator());
}
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
- .AddMember(StringRef("Folder"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator())
+ .AddMember(StringRef("Folder"), Value(folderPath.c_str(), aznumeric_caster(folderPath.Native().size()), m_settings.GetAllocator()), m_settings.GetAllocator())
.AddMember(StringRef("Specializations"), AZStd::move(specialzationArray), m_settings.GetAllocator());
- auto callback = [this, &fileList, &specializations, &pointer, &folderPath](const char* filename, bool isFile) -> bool
+
+ auto CreateSettingsFindCallback = [this, &fileList, &specializations, &pointer, &folderPath](bool isPlatformFile)
{
- if (isFile)
- {
- if (fileList.size() >= MaxRegistryFolderEntries)
- {
- AZ_Error("Settings Registry", false, "Too many files in registry folder.");
- AZStd::scoped_lock lock(m_settingMutex);
- pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
- .AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator())
- .AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator())
- .AddMember(StringRef("File"), Value(filename, m_settings.GetAllocator()), m_settings.GetAllocator());
- return false;
- }
-
- fileList.push_back();
- RegistryFile& registryFile = fileList.back();
- if (!ExtractFileDescription(registryFile, filename, specializations))
- {
- fileList.pop_back();
- }
- }
- return true;
- };
- SystemFile::FindFiles(folderPath.c_str(), callback);
-
-
- if (!platform.empty())
- {
- // Move the folderPath prefix back to the supplied path before the wildcard
- folderPath.erase(platformKeyOffset);
- folderPath += PlatformFolder;
- folderPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
- folderPath += platform;
- folderPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
- folderPath.push_back('*');
-
- auto platformCallback = [this, &fileList, &specializations, &pointer, &folderPath](const char* filename, bool isFile) -> bool
+ return [this, &fileList, &specializations, &pointer, &folderPath, isPlatformFile](AZStd::string_view filename, bool isFile) -> bool
{
if (isFile)
{
@@ -791,8 +762,8 @@ namespace AZ
AZStd::scoped_lock lock(m_settingMutex);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
.AddMember(StringRef("Error"), StringRef("Too many files in registry folder."), m_settings.GetAllocator())
- .AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.size()), m_settings.GetAllocator()), m_settings.GetAllocator())
- .AddMember(StringRef("File"), Value(filename, m_settings.GetAllocator()), m_settings.GetAllocator());
+ .AddMember(StringRef("Path"), Value(folderPath.c_str(), aznumeric_caster(folderPath.Native().size()), m_settings.GetAllocator()), m_settings.GetAllocator())
+ .AddMember(StringRef("File"), Value(filename.data(), aznumeric_caster(filename.size()), m_settings.GetAllocator()), m_settings.GetAllocator());
return false;
}
@@ -800,7 +771,7 @@ namespace AZ
RegistryFile& registryFile = fileList.back();
if (ExtractFileDescription(registryFile, filename, specializations))
{
- registryFile.m_isPlatformFile = true;
+ registryFile.m_isPlatformFile = isPlatformFile;
}
else
{
@@ -809,7 +780,42 @@ namespace AZ
}
return true;
};
- SystemFile::FindFiles(folderPath.c_str(), platformCallback);
+ };
+
+ struct FindFilesPayload
+ {
+ bool m_isPlatformFile{};
+ AZStd::fixed_vector m_pathSegmentsToAppend;
+ };
+
+ AZStd::fixed_vector findFilesPayloads{ {false} };
+ if (!platform.empty())
+ {
+ findFilesPayloads.push_back(FindFilesPayload{ true, { PlatformFolder, platform } });
+ }
+
+ for (const FindFilesPayload& findFilesPayload : findFilesPayloads)
+ {
+ // Erase back to initial path
+ folderPath.Native().erase(platformKeyOffset);
+ for (AZStd::string_view pathSegmentToAppend : findFilesPayload.m_pathSegmentsToAppend)
+ {
+ folderPath /= pathSegmentToAppend;
+ }
+
+ auto findFilesCallback = CreateSettingsFindCallback(findFilesPayload.m_isPlatformFile);
+ if (AZ::IO::FileIOBase* fileIo = m_useFileIo ? AZ::IO::FileIOBase::GetInstance() : nullptr; fileIo != nullptr)
+ {
+ auto FileIoToSystemFileFindFiles = [findFilesCallback = AZStd::move(findFilesCallback), fileIo](const char* filePath) -> bool
+ {
+ return findFilesCallback(AZ::IO::PathView(filePath).Filename().Native(), !fileIo->IsDirectory(filePath));
+ };
+ fileIo->FindFiles(folderPath.c_str(), "*", FileIoToSystemFileFindFiles);
+ }
+ else
+ {
+ SystemFile::FindFiles((folderPath / "*").c_str(), findFilesCallback);
+ }
}
if (!fileList.empty())
@@ -831,16 +837,14 @@ namespace AZ
// Load the registry files in the sorted order.
for (RegistryFile& registryFile : fileList)
{
- folderPath.erase(platformKeyOffset); // Erase all characters after the platformKeyOffset
+ folderPath.Native().erase(platformKeyOffset); // Erase all characters after the platformKeyOffset
if (registryFile.m_isPlatformFile)
{
- folderPath += PlatformFolder;
- folderPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
- folderPath += platform;
- folderPath.push_back(AZ_CORRECT_DATABASE_SEPARATOR);
+ folderPath /= PlatformFolder;
+ folderPath /= platform;
}
- folderPath += registryFile.m_relativePath;
+ folderPath /= registryFile.m_relativePath;
if (!registryFile.m_isPatch)
{
@@ -1027,39 +1031,44 @@ namespace AZ
return false;
}
- bool SettingsRegistryImpl::ExtractFileDescription(RegistryFile& output, const char* filename, const Specializations& specializations)
+ bool SettingsRegistryImpl::ExtractFileDescription(RegistryFile& output, AZStd::string_view filename, const Specializations& specializations)
{
- if (!filename || filename[0] == 0)
+ static constexpr auto PatchExtensionWithDot = AZStd::fixed_string<32>(".") + PatchExtension;
+ static constexpr auto ExtensionWithDot = AZStd::fixed_string<32>(".") + Extension;
+ static constexpr AZ::IO::PathView PatchExtensionView(PatchExtensionWithDot);
+ static constexpr AZ::IO::PathView ExtensionView(ExtensionWithDot);
+
+ if (filename.empty())
{
AZ_Error("Settings Registry", false, "Settings file without name found");
return false;
}
- AZStd::string_view filePath{ filename };
- const size_t filePathSize = filePath.size();
+ AZ::IO::PathView filePath{ filename };
+ const size_t filePathSize = filePath.Native().size();
// The filePath.empty() check makes sure that the file extension after the final isn't added to the output.m_tags
- AZStd::optional pathTag = AZ::StringFunc::TokenizeNext(filePath, '.');
- for (; pathTag && !filePath.empty(); pathTag = AZ::StringFunc::TokenizeNext(filePath, '.'))
+ auto AppendSpecTags = [&output](AZStd::string_view pathTag)
{
- output.m_tags.push_back(Specializations::Hash(*pathTag));
- }
+ output.m_tags.push_back(Specializations::Hash(pathTag));
+ };
+ AZ::StringFunc::TokenizeVisitor(filePath.Stem().Native(), AppendSpecTags, '.');
// If token is invalid, then the filename has no characters and therefore no extension
- if (pathTag)
+ if (AZ::IO::PathView fileExtension = filePath.Extension(); !fileExtension.empty())
{
- if (pathTag->size() >= AZStd::char_traits::length(PatchExtension) && azstrnicmp(pathTag->data(), PatchExtension, pathTag->size()) == 0)
+ if (fileExtension == PatchExtensionView)
{
output.m_isPatch = true;
}
- else if (pathTag->size() != AZStd::char_traits::length(Extension) || azstrnicmp(pathTag->data(), Extension, pathTag->size()) != 0)
+ else if (fileExtension != ExtensionView)
{
return false;
}
}
else
{
- AZ_Error("Settings Registry", false, R"(Settings file without extension found: "%s")", filename);
+ AZ_Error("Settings Registry", false, R"(Settings file without extension found: "%.*s")", AZ_STRING_ARG(filename));
return false;
}
@@ -1074,7 +1083,7 @@ namespace AZ
{
if (*currentIt == *(currentIt - 1))
{
- AZ_Error("Settings Registry", false, R"(One or more tags are duplicated in registry file "%s")", filename);
+ AZ_Error("Settings Registry", false, R"(One or more tags are duplicated in registry file "%.*s")", AZ_STRING_ARG(filename));
return false;
}
++currentIt;
@@ -1103,7 +1112,7 @@ namespace AZ
}
else
{
- AZ_Error("Settings Registry", false, R"(Found relative path to settings file "%s" is too long.)", filename);
+ AZ_Error("Settings Registry", false, R"(Found relative path to settings file "%.*s" is too long.)", AZ_STRING_ARG(filename));
return false;
}
}
@@ -1116,8 +1125,8 @@ namespace AZ
Pointer pointer(AZ_SETTINGS_REGISTRY_HISTORY_KEY "/-");
- SystemFile file;
- if (!file.Open(path, SystemFile::OpenMode::SF_OPEN_READ_ONLY))
+ FileReader fileReader(m_useFileIo ? AZ::IO::FileIOBase::GetInstance(): nullptr, path);
+ if (!fileReader.IsOpen())
{
AZ_Error("Settings Registry", false, R"(Unable to open registry file "%s".)", path);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
@@ -1126,7 +1135,7 @@ namespace AZ
return false;
}
- u64 fileSize = file.Length();
+ u64 fileSize = fileReader.Length();
if (fileSize == 0)
{
AZ_Warning("Settings Registry", false, R"(Registry file "%s" is 0 bytes in length. There is no nothing to merge)", path);
@@ -1136,9 +1145,10 @@ namespace AZ
.AddMember(StringRef("Path"), Value(path, m_settings.GetAllocator()), m_settings.GetAllocator());
return false;
}
+
scratchBuffer.clear();
scratchBuffer.resize_no_construct(fileSize + 1);
- if (file.Read(fileSize, scratchBuffer.data()) != fileSize)
+ if (fileReader.Read(fileSize, scratchBuffer.data()) != fileSize)
{
AZ_Error("Settings Registry", false, R"(Unable to read registry file "%s".)", path);
pointer.Create(m_settings, m_settings.GetAllocator()).SetObject()
@@ -1268,4 +1278,9 @@ namespace AZ
{
applyPatchSettings = m_applyPatchSettings;
}
+
+ void SettingsRegistryImpl::SetUseFileIO(bool useFileIo)
+ {
+ m_useFileIo = useFileIo;
+ }
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h
index 036f5c6596..ac214711b8 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryImpl.h
@@ -35,6 +35,10 @@ namespace AZ
static constexpr size_t MaxRegistryFolderEntries = 128;
SettingsRegistryImpl();
+ //! @param useFileIo - If true attempt to redirect
+ //! file read operations through the FileIOBase instance first before falling back to SystemFile
+ //! otherwise always use SystemFile
+ explicit SettingsRegistryImpl(bool useFileIo);
AZ_DISABLE_COPY_MOVE(SettingsRegistryImpl);
~SettingsRegistryImpl() override = default;
@@ -83,6 +87,8 @@ namespace AZ
void SetApplyPatchSettings(const AZ::JsonApplyPatchSettings& applyPatchSettings) override;
void GetApplyPatchSettings(AZ::JsonApplyPatchSettings& applyPatchSettings) override;
+ void SetUseFileIO(bool useFileIo) override;
+
private:
using TagList = AZStd::fixed_vector;
struct RegistryFile
@@ -104,7 +110,7 @@ namespace AZ
// Compares if lhs is less than rhs in terms of processing order. This can also detect and report conflicts.
bool IsLessThan(bool& collisionFound, const RegistryFile& lhs, const RegistryFile& rhs, const Specializations& specializations,
const rapidjson::Pointer& historyPointer, AZStd::string_view folderPath);
- bool ExtractFileDescription(RegistryFile& output, const char* filename, const Specializations& specializations);
+ bool ExtractFileDescription(RegistryFile& output, AZStd::string_view filename, const Specializations& specializations);
bool MergeSettingsFileInternal(const char* path, Format format, AZStd::string_view rootKey, AZStd::vector& scratchBuffer);
void SignalNotifier(AZStd::string_view jsonPath, Type type);
@@ -119,5 +125,7 @@ namespace AZ
JsonSerializerSettings m_serializationSettings;
JsonDeserializerSettings m_deserializationSettings;
JsonApplyPatchSettings m_applyPatchSettings;
+
+ bool m_useFileIo{};
};
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
index 71ffece892..da7110e36e 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
@@ -6,6 +6,8 @@
*
*/
+#include
+#include