merging latest development
Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
+4
-2
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
+94
-94
@@ -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)
|
||||
|
||||
+65
-67
@@ -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)
|
||||
|
||||
+83
-82
@@ -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)
|
||||
|
||||
-125
@@ -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()
|
||||
+139
-134
@@ -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)
|
||||
|
||||
+88
-90
@@ -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)
|
||||
|
||||
+97
-87
@@ -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)
|
||||
|
||||
+92
-83
@@ -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)
|
||||
|
||||
+160
-122
@@ -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)
|
||||
|
||||
+95
-79
@@ -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)
|
||||
|
||||
+114
-99
@@ -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)
|
||||
|
||||
+114
-92
@@ -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)
|
||||
|
||||
+93
-89
@@ -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)
|
||||
|
||||
+135
-125
@@ -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)
|
||||
|
||||
+84
-81
@@ -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)
|
||||
|
||||
+63
-65
@@ -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)
|
||||
|
||||
+92
-94
@@ -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)
|
||||
|
||||
+103
-109
@@ -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)
|
||||
|
||||
+114
-98
@@ -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)
|
||||
|
||||
+71
-73
@@ -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)
|
||||
|
||||
+91
-95
@@ -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)
|
||||
|
||||
+68
-74
@@ -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)
|
||||
|
||||
+55
-59
@@ -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)
|
||||
|
||||
+183
-162
@@ -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)
|
||||
|
||||
+109
-112
@@ -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)
|
||||
|
||||
+136
-131
@@ -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)
|
||||
|
||||
+115
-116
@@ -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)
|
||||
|
||||
+194
-175
@@ -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)
|
||||
|
||||
+132
-130
@@ -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)
|
||||
|
||||
+99
-99
@@ -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)
|
||||
|
||||
+113
@@ -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)
|
||||
+103
-101
@@ -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)
|
||||
|
||||
+107
-96
@@ -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)
|
||||
|
||||
+113
-101
@@ -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)
|
||||
|
||||
+97
-96
@@ -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)
|
||||
|
||||
-103
@@ -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()
|
||||
+126
@@ -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)
|
||||
+88
-90
@@ -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)
|
||||
|
||||
+132
-125
@@ -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)
|
||||
|
||||
+49
-54
@@ -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)
|
||||
|
||||
+111
-117
@@ -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)
|
||||
|
||||
+112
-118
@@ -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)
|
||||
|
||||
+71
-70
@@ -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)
|
||||
|
||||
+71
-68
@@ -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)
|
||||
|
||||
+65
-69
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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
|
||||
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
|
||||
@pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155")
|
||||
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
|
||||
@pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155")
|
||||
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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
-140
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
-53
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
@@ -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]
|
||||
)
|
||||
+1
-1
@@ -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)
|
||||
|
||||
@@ -140,9 +140,6 @@
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="showGrid">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -201,6 +198,11 @@
|
||||
<header>AzToolsFramework/AssetBrowser/Search/SearchWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzQtComponents::TableView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>AzQtComponents/Components/Widgets/TableView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzToolsFramework::AssetBrowser::AssetBrowserTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
@@ -214,7 +216,7 @@
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AzToolsFramework::AssetBrowser::AssetBrowserTableView</class>
|
||||
<extends>QTableView</extends>
|
||||
<extends>AzQtComponents::TableView</extends>
|
||||
<header>AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
||||
@@ -8,11 +8,21 @@
|
||||
|
||||
#include "QtEditorApplication.h"
|
||||
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/API/ApplicationAPI_Linux.h>
|
||||
#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::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AZStd::chrono::milliseconds>(now).time_since_epoch();
|
||||
}
|
||||
} // namespace EditorInternal
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzToolsFramework/Application/ToolsApplication.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
#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);
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -92,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
|
||||
{
|
||||
@@ -212,9 +211,6 @@ private:
|
||||
// EditorEntityViewportInteractionRequestBus overrides ...
|
||||
void FindVisibleEntities(AZStd::vector<AZ::EntityId>& 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;
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
#define CRYINCLUDE_EDITOR_INCLUDE_IEDITORCLASSFACTORY_H
|
||||
#pragma once
|
||||
|
||||
#include <CryCommon/platform.h>
|
||||
#include <vector>
|
||||
#include <QtCore/QString>
|
||||
#include <AzCore/Math/Guid.h>
|
||||
|
||||
#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"
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -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)
|
||||
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>EditorDummy</string>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.O3DE.Editor</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -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 <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Process/ProcessWatcher.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
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<AZStd::string> 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;
|
||||
}
|
||||
|
||||
@@ -51,4 +51,5 @@ ly_add_target(
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AzQtComponents
|
||||
Legacy::EditorCore
|
||||
)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
namespace AZ::Debug
|
||||
{
|
||||
template<typename... T>
|
||||
@@ -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<Profiler>::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<Profiler>::Get(); profiler)
|
||||
{
|
||||
profiler->EndRegion(budget);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -72,6 +72,7 @@ namespace AZ
|
||||
{
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
bool fileFound = false;
|
||||
if (AZ::IO::FixedMaxPath projectModulePath;
|
||||
settingsRegistry->Get(projectModulePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectConfigurationBinPath))
|
||||
{
|
||||
@@ -79,6 +80,23 @@ namespace AZ
|
||||
if (AZ::IO::SystemFile::Exists(projectModulePath.c_str()))
|
||||
{
|
||||
m_fileName.assign(projectModulePath.c_str(), projectModulePath.Native().size());
|
||||
fileFound = true;
|
||||
}
|
||||
}
|
||||
if (!fileFound)
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath installedBinariesPath;
|
||||
settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
|
||||
{
|
||||
if (AZ::IO::FixedMaxPath engineRootFolder;
|
||||
settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
|
||||
{
|
||||
installedBinariesPath = engineRootFolder / installedBinariesPath / fullFilePath;
|
||||
if (AZ::IO::SystemFile::Exists(installedBinariesPath.c_str()))
|
||||
{
|
||||
m_fileName.assign(installedBinariesPath.c_str(), installedBinariesPath.Native().size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <pwd.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -39,6 +40,14 @@ namespace AZ
|
||||
AZ::IO::FixedMaxPath path{homePath};
|
||||
return path.Native();
|
||||
}
|
||||
|
||||
struct passwd* pass = getpwuid(getuid());
|
||||
if (pass)
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{pass->pw_dir};
|
||||
return path.Native();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace AZ::IO::ArchiveInternal
|
||||
return 0;
|
||||
}
|
||||
|
||||
nTotal = (AZStd::min)(nTotal, GetFileSize() - m_nCurSeek);
|
||||
nTotal = AZStd::min<size_t>(nTotal, GetFileSize() - m_nCurSeek);
|
||||
|
||||
int64_t nReadBytes = GetFile()->ReadData(pDest, m_nCurSeek, nTotal);
|
||||
if (nReadBytes == -1)
|
||||
|
||||
@@ -9,8 +9,19 @@
|
||||
#include <AzFramework/Viewport/ClickDetector.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
|
||||
#include <AzCore/std/chrono/clocks.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
ClickDetector::ClickDetector()
|
||||
{
|
||||
m_timeNowFn = []
|
||||
{
|
||||
const auto now = AZStd::chrono::high_resolution_clock::now();
|
||||
return AZStd::chrono::time_point_cast<AZStd::chrono::milliseconds>(now).time_since_epoch();
|
||||
};
|
||||
}
|
||||
|
||||
ClickDetector::ClickOutcome ClickDetector::DetectClick(const ClickEvent clickEvent, const ScreenVector& cursorDelta)
|
||||
{
|
||||
const auto previousDetectionState = m_detectionState;
|
||||
@@ -26,11 +37,13 @@ namespace AzFramework
|
||||
|
||||
if (clickEvent == ClickEvent::Down)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto now = m_timeNowFn();
|
||||
if (m_tryBeginTime)
|
||||
{
|
||||
const std::chrono::duration<float> diff = now - m_tryBeginTime.value();
|
||||
if (diff.count() < m_doubleClickInterval)
|
||||
using FloatingPointSeconds = AZStd::chrono::duration<float, AZStd::chrono::seconds::period>;
|
||||
|
||||
const auto diff = now - m_tryBeginTime.value();
|
||||
if (FloatingPointSeconds(diff).count() < m_doubleClickInterval)
|
||||
{
|
||||
return ClickOutcome::Nil;
|
||||
}
|
||||
@@ -43,7 +56,8 @@ namespace AzFramework
|
||||
}
|
||||
else if (clickEvent == ClickEvent::Up)
|
||||
{
|
||||
const auto clickOutcome = [detectionState = m_detectionState] {
|
||||
const auto clickOutcome = [detectionState = m_detectionState]
|
||||
{
|
||||
if (detectionState == DetectionState::WaitingForMove)
|
||||
{
|
||||
return ClickOutcome::Click;
|
||||
@@ -66,4 +80,9 @@ namespace AzFramework
|
||||
|
||||
return ClickOutcome::Nil;
|
||||
}
|
||||
|
||||
void ClickDetector::OverrideTimeNowFn(AZStd::function<AZStd::chrono::milliseconds()> timeNowFn)
|
||||
{
|
||||
m_timeNowFn = AZStd::move(timeNowFn);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
|
||||
#include <chrono>
|
||||
@@ -21,10 +22,9 @@ namespace AzFramework
|
||||
//! (mouse down with movement and then mouse up).
|
||||
class ClickDetector
|
||||
{
|
||||
//! Alias for recording time of mouse down events
|
||||
using Time = std::chrono::time_point<std::chrono::steady_clock>;
|
||||
|
||||
public:
|
||||
ClickDetector();
|
||||
|
||||
//! Internal representation of click event (map from external event for this when
|
||||
//! calling DetectClick).
|
||||
enum class ClickEvent
|
||||
@@ -51,6 +51,10 @@ namespace AzFramework
|
||||
void SetDoubleClickInterval(float doubleClickInterval);
|
||||
//! Override the dead zone before a 'move' outcome will be triggered.
|
||||
void SetDeadZone(float deadZone);
|
||||
//! Override how the current time is retrieved.
|
||||
//! This is helpful to override when it comes to simulating different passages of
|
||||
//! time to avoid double click issues in tests for example.
|
||||
void OverrideTimeNowFn(AZStd::function<AZStd::chrono::milliseconds()> timeNowFn);
|
||||
|
||||
private:
|
||||
//! Internal state of ClickDetector based on incoming events.
|
||||
@@ -65,7 +69,9 @@ namespace AzFramework
|
||||
float m_deadZone = 2.0f; //!< How far to move before a click is cancelled (when Move will fire).
|
||||
float m_doubleClickInterval = 0.4f; //!< Default double click interval, can be overridden.
|
||||
DetectionState m_detectionState; //!< Internal state of ClickDetector.
|
||||
AZStd::optional<Time> m_tryBeginTime; //!< Mouse down time (happens each mouse down, helps with double click handling).
|
||||
//! Mouse down time (happens each mouse down, helps with double click handling).
|
||||
AZStd::optional<AZStd::chrono::milliseconds> m_tryBeginTime;
|
||||
AZStd::function<AZStd::chrono::milliseconds()> m_timeNowFn; //!< Interface to query the current time.
|
||||
};
|
||||
|
||||
inline void ClickDetector::SetDoubleClickInterval(const float doubleClickInterval)
|
||||
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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 <AzCore/std/typetraits/integral_constant.h>
|
||||
#include <AzFramework/API/ApplicationAPI_Linux.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
|
||||
#define explicit ExplicitIsACXXKeyword
|
||||
#include <xcb/xkb.h>
|
||||
#undef explicit
|
||||
#include <xkbcommon/xkbcommon-keysyms.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xkbcommon/xkbcommon-x11.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class InputDeviceKeyboardXcb
|
||||
: public InputDeviceKeyboard::Implementation
|
||||
, public LinuxXcbEventHandlerBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(InputDeviceKeyboardXcb, AZ::SystemAllocator, 0);
|
||||
|
||||
using InputDeviceKeyboard::Implementation::Implementation;
|
||||
InputDeviceKeyboardXcb(InputDeviceKeyboard& inputDevice)
|
||||
: InputDeviceKeyboard::Implementation(inputDevice)
|
||||
{
|
||||
LinuxXcbEventHandlerBus::Handler::BusConnect();
|
||||
|
||||
auto* interface = AzFramework::LinuxXcbConnectionManagerInterface::Get();
|
||||
if (!interface)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "XCB interface not available");
|
||||
return;
|
||||
}
|
||||
|
||||
auto* connection = AzFramework::LinuxXcbConnectionManagerInterface::Get()->GetXcbConnection();
|
||||
if (!connection)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "XCB connection not available");
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<xcb_xkb_use_extension_reply_t, DeleterForFreeFn<::std::free>> xkbUseExtensionReply{
|
||||
xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
|
||||
};
|
||||
if (!xkbUseExtensionReply)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
|
||||
return;
|
||||
}
|
||||
if (!xkbUseExtensionReply->supported)
|
||||
{
|
||||
AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
|
||||
return;
|
||||
}
|
||||
|
||||
m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
|
||||
|
||||
m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
|
||||
m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
|
||||
m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool IsConnected() const override
|
||||
{
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool HasTextEntryStarted() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override
|
||||
{
|
||||
}
|
||||
|
||||
void TextEntryStop() override
|
||||
{
|
||||
}
|
||||
|
||||
void TickInputDevice() override
|
||||
{
|
||||
ProcessRawEventQueues();
|
||||
}
|
||||
|
||||
void HandleXcbEvent(xcb_generic_event_t* event) override
|
||||
{
|
||||
if (!IsConnected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event->response_type & ~0x80)
|
||||
{
|
||||
case XCB_KEY_PRESS:
|
||||
{
|
||||
auto* keyPress = reinterpret_cast<xcb_key_press_event_t*>(event);
|
||||
|
||||
const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
|
||||
if (key)
|
||||
{
|
||||
QueueRawKeyEvent(*key, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XCB_KEY_RELEASE:
|
||||
{
|
||||
auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(event);
|
||||
|
||||
const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
|
||||
if (key)
|
||||
{
|
||||
QueueRawKeyEvent(*key, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const
|
||||
{
|
||||
const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
|
||||
|
||||
switch(keysym)
|
||||
{
|
||||
case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
|
||||
case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
|
||||
case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
|
||||
case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
|
||||
case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
|
||||
case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
|
||||
case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
|
||||
case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
|
||||
case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
|
||||
case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
|
||||
case XKB_KEY_A:
|
||||
case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
|
||||
case XKB_KEY_B:
|
||||
case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
|
||||
case XKB_KEY_C:
|
||||
case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
|
||||
case XKB_KEY_D:
|
||||
case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
|
||||
case XKB_KEY_E:
|
||||
case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
|
||||
case XKB_KEY_F:
|
||||
case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
|
||||
case XKB_KEY_G:
|
||||
case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
|
||||
case XKB_KEY_H:
|
||||
case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
|
||||
case XKB_KEY_I:
|
||||
case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
|
||||
case XKB_KEY_J:
|
||||
case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
|
||||
case XKB_KEY_K:
|
||||
case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
|
||||
case XKB_KEY_L:
|
||||
case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
|
||||
case XKB_KEY_M:
|
||||
case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
|
||||
case XKB_KEY_N:
|
||||
case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
|
||||
case XKB_KEY_O:
|
||||
case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
|
||||
case XKB_KEY_P:
|
||||
case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
|
||||
case XKB_KEY_Q:
|
||||
case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
|
||||
case XKB_KEY_R:
|
||||
case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
|
||||
case XKB_KEY_S:
|
||||
case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
|
||||
case XKB_KEY_T:
|
||||
case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
|
||||
case XKB_KEY_U:
|
||||
case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
|
||||
case XKB_KEY_V:
|
||||
case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
|
||||
case XKB_KEY_W:
|
||||
case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
|
||||
case XKB_KEY_X:
|
||||
case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
|
||||
case XKB_KEY_Y:
|
||||
case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
|
||||
case XKB_KEY_Z:
|
||||
case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
|
||||
case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
|
||||
case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
|
||||
case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
|
||||
case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
|
||||
case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
|
||||
case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
|
||||
case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
|
||||
case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
|
||||
case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
|
||||
case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
|
||||
case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
|
||||
case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
|
||||
case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
|
||||
case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
|
||||
case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
|
||||
case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
|
||||
case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
|
||||
case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
|
||||
case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
|
||||
case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
|
||||
case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
|
||||
case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
|
||||
case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
|
||||
case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
|
||||
case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
|
||||
case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
|
||||
case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
|
||||
case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
|
||||
case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
|
||||
case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
|
||||
case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
|
||||
case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
|
||||
case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
|
||||
case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
|
||||
case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
|
||||
case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
|
||||
case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
|
||||
case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
|
||||
case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
|
||||
case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
|
||||
case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
|
||||
case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
|
||||
case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
|
||||
case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
|
||||
case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
|
||||
case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
|
||||
case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
|
||||
case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
|
||||
case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
|
||||
case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
|
||||
case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
|
||||
case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
|
||||
case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
|
||||
case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
|
||||
case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
|
||||
case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
|
||||
case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
|
||||
case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
|
||||
case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
|
||||
case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
|
||||
case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
|
||||
case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
|
||||
case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
|
||||
case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
|
||||
case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
|
||||
case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
|
||||
case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
|
||||
case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
|
||||
case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
|
||||
case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
|
||||
case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
|
||||
case XKB_KEY_grave:
|
||||
case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
|
||||
case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
|
||||
case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
|
||||
case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
|
||||
case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<auto freeFn>
|
||||
using DeleterForFreeFn = AZStd::integral_constant<decltype(freeFn), freeFn>;
|
||||
|
||||
AZStd::unique_ptr<xkb_context, DeleterForFreeFn<xkb_context_unref>> m_xkbContext;
|
||||
AZStd::unique_ptr<xkb_keymap, DeleterForFreeFn<xkb_keymap_unref>> m_xkbKeymap;
|
||||
AZStd::unique_ptr<xkb_state, DeleterForFreeFn<xkb_state_unref>> m_xkbState;
|
||||
int m_coreDeviceId{-1};
|
||||
bool m_initialized{false};
|
||||
};
|
||||
|
||||
InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
|
||||
{
|
||||
return aznew InputDeviceKeyboardXcb(inputDevice);
|
||||
}
|
||||
} // namespace AzFramework
|
||||
+9
-1
@@ -62,8 +62,16 @@ namespace AzFramework
|
||||
|
||||
uint32_t eventMask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
|
||||
const uint32_t interestedEvents =
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY
|
||||
| XCB_EVENT_MASK_BUTTON_PRESS
|
||||
| XCB_EVENT_MASK_BUTTON_RELEASE
|
||||
| XCB_EVENT_MASK_KEY_PRESS
|
||||
| XCB_EVENT_MASK_KEY_RELEASE
|
||||
| XCB_EVENT_MASK_POINTER_MOTION
|
||||
;
|
||||
uint32_t valueList[] = { xcbRootScreen->black_pixel,
|
||||
XCB_EVENT_MASK_STRUCTURE_NOTIFY };
|
||||
interestedEvents };
|
||||
|
||||
xcb_void_cookie_t xcbCheckResult;
|
||||
|
||||
|
||||
@@ -11,10 +11,16 @@
|
||||
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
|
||||
|
||||
find_library(XCB_LIBRARY xcb)
|
||||
find_library(XCB_XKB_LIBRARY xcb-xkb)
|
||||
find_library(XKBCOMMON_LIBRARY xkbcommon)
|
||||
find_library(XKBCOMMON_X11_LIBRARY xkbcommon-x11)
|
||||
|
||||
set(LY_BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
${XCB_LIBRARY}
|
||||
${XKBCOMMON_LIBRARY}
|
||||
${XKBCOMMON_X11_LIBRARY}
|
||||
${XCB_XKB_LIBRARY}
|
||||
)
|
||||
|
||||
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
|
||||
|
||||
@@ -25,7 +25,7 @@ set(FILES
|
||||
AzFramework/Windowing/NativeWindow_Linux_xcb.h
|
||||
AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Unimplemented.cpp
|
||||
AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp
|
||||
|
||||
+16
@@ -18,6 +18,7 @@ namespace AzManipulatorTestFramework
|
||||
class ImmediateModeActionDispatcher
|
||||
: public ActionDispatcher<ImmediateModeActionDispatcher>
|
||||
, public AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
|
||||
, public AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler
|
||||
{
|
||||
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
|
||||
using KeyboardModifiers = AzToolsFramework::ViewportInteraction::KeyboardModifiers;
|
||||
@@ -50,6 +51,9 @@ namespace AzManipulatorTestFramework
|
||||
// EditorModifierKeyRequestBus overrides ...
|
||||
KeyboardModifiers QueryKeyboardModifiers() override;
|
||||
|
||||
// EditorViewportInputTimeNowRequestBus overrides ...
|
||||
AZStd::chrono::milliseconds EditorViewportInputTimeNow() override;
|
||||
|
||||
protected:
|
||||
// ActionDispatcher ...
|
||||
void SetSnapToGridImpl(bool enabled) override;
|
||||
@@ -79,6 +83,9 @@ namespace AzManipulatorTestFramework
|
||||
|
||||
mutable AZStd::unique_ptr<MouseInteractionEvent> m_event;
|
||||
ManipulatorViewportInteraction& m_viewportManipulatorInteraction;
|
||||
|
||||
//! Current time that ticks up after each call to EditorViewportInputTimeNow.
|
||||
AZStd::chrono::milliseconds m_timeNow = AZStd::chrono::milliseconds(0);
|
||||
};
|
||||
|
||||
template<typename ActualT, typename ExpectedT>
|
||||
@@ -106,4 +113,13 @@ namespace AzManipulatorTestFramework
|
||||
{
|
||||
return GetMouseInteractionEvent()->m_mouseInteraction.m_keyboardModifiers;
|
||||
}
|
||||
|
||||
inline AZStd::chrono::milliseconds ImmediateModeActionDispatcher::EditorViewportInputTimeNow()
|
||||
{
|
||||
// step the time for each call to be greater than the minimum time required for a double click to register
|
||||
// note: the time increment is very high to ensure any potential system changes to settings such as double
|
||||
// click interval will not be impacted
|
||||
m_timeNow += AZStd::chrono::milliseconds(10000);
|
||||
return m_timeNow;
|
||||
}
|
||||
} // namespace AzManipulatorTestFramework
|
||||
|
||||
@@ -33,10 +33,12 @@ namespace AzManipulatorTestFramework
|
||||
: m_viewportManipulatorInteraction(viewportManipulatorInteraction)
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
ImmediateModeActionDispatcher::~ImmediateModeActionDispatcher()
|
||||
{
|
||||
AzToolsFramework::ViewportInteraction::EditorViewportInputTimeNowRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <AzToolsFramework/API/ViewportEditorModeTrackerNotificationBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! The AZ::Interface of the central editor mode tracker for all viewports.
|
||||
class ViewportEditorModeTrackerInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(ViewportEditorModeTrackerInterface, "{7D72A4F7-2147-4ED9-A315-E456A3BE3CF6}");
|
||||
|
||||
virtual ~ViewportEditorModeTrackerInterface() = default;
|
||||
|
||||
//! Activates the specified editor mode for the specified viewport.
|
||||
virtual AZ::Outcome<void, AZStd::string> ActivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0;
|
||||
|
||||
//! Deactivates the specified editor mode for the specified viewport.
|
||||
virtual AZ::Outcome<void, AZStd::string> DeactivateMode(
|
||||
const ViewportEditorModeInfo& viewportEditorModeInfo, ViewportEditorMode mode) = 0;
|
||||
|
||||
//! Attempts to retrieve the editor mode state for the specified viewport, otherwise returns nullptr.
|
||||
virtual const ViewportEditorModesInterface* GetViewportEditorModes(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0;
|
||||
|
||||
//! Returns the number of viewports currently being tracked.
|
||||
virtual size_t GetTrackedViewportCount() const = 0;
|
||||
|
||||
//! Returns true if the specified viewport is being tracked, otherwise false.
|
||||
virtual bool IsViewportModeTracked(const ViewportEditorModeInfo& viewportEditorModeInfo) const = 0;
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user