Merge branch 'development' into cmake/SPEC-7179

monroegm-disable-blank-issue-2
Esteban Papp 4 years ago
commit 074518454c

@ -6,13 +6,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
import logging import logging
import os import os
import tempfile import psutil
import ly_test_tools.log.log_monitor import ly_test_tools.log.log_monitor
import ly_test_tools.environment.process_utils as process_utils import ly_test_tools.environment.process_utils as process_utils
import ly_test_tools.environment.waiter as waiter import ly_test_tools.environment.waiter as waiter
from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole
from ly_remote_console.remote_console_commands import send_command_and_expect_response as send_command_and_expect_response from ly_remote_console.remote_console_commands import send_command_and_expect_response as send_command_and_expect_response
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -95,7 +95,7 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
return port_listening return port_listening
if null_renderer: if null_renderer:
launcher.args.extend(["-NullRenderer"]) launcher.args.extend(["-rhi=Null"])
# Start the Launcher # Start the Launcher
with launcher.start(): with launcher.start():
@ -110,8 +110,8 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
# Load the specified level in the launcher # Load the specified level in the launcher
send_command_and_expect_response(remote_console_instance, send_command_and_expect_response(remote_console_instance,
f"map {level}", f"LoadLevel {level}",
"LEVEL_LOAD_COMPLETE", timeout=30) "LEVEL_LOAD_END", timeout=30)
# Monitor the console for expected lines # Monitor the console for expected lines
for line in expected_lines: for line in expected_lines:

@ -77,7 +77,6 @@ class TestAllComponentsIndepthTests(object):
unexpected_lines=unexpected_lines, unexpected_lines=unexpected_lines,
halt_on_unexpected=True, halt_on_unexpected=True,
cfg_args=[level], cfg_args=[level],
auto_test_mode=False,
null_renderer=False, null_renderer=False,
) )

@ -36,8 +36,8 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
:return: None :return: None
""" """
PREPROCESS_INSTANCE_COUNT = 24 PREPROCESS_INSTANCE_COUNT = 44
POSTPROCESS_INSTANCE_COUNT = 18 POSTPROCESS_INSTANCE_COUNT = 34
# Create empty level # Create empty level
self.test_success = self.create_level( self.test_success = self.create_level(
@ -62,25 +62,7 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0) dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0)
# Add entity with Mesh to replicate creation of hills # Add entity with Mesh to replicate creation of hills
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 40.0, 40.0, 40.0) hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 10.0)
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# Increase Box Shape size to encompass the hills
vegetation.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(100.0, 100.0, 100.0))
# Set a Min Altitude of 38 and Max of 40 in Vegetation Altitude Filter # 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 Min", 38.0)

@ -9,9 +9,10 @@ import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__))) sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import azlmbr.asset as asset import azlmbr.asset as asset
import azlmbr.components as components
import azlmbr.legacy.general as general import azlmbr.legacy.general as general
import azlmbr.bus as bus import azlmbr.bus as bus
import azlmbr.entity as EntityId import azlmbr.entity as entity
import azlmbr.editor as editor import azlmbr.editor as editor
import azlmbr.math as math import azlmbr.math as math
import azlmbr.paths import azlmbr.paths
@ -83,18 +84,12 @@ class TestDynamicSliceInstanceSpawnerEmbeddedEditor(EditorTestHelper):
self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances") self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
self.test_success = self.test_success and num_found == num_expected_instances self.test_success = self.test_success and num_found == num_expected_instances
# 5) Create a new entity with a Camera component for testing in the launcher # 5) Move the default Camera entity for testing in the launcher
cam_position = math.Vector3(512.0, 500.0, 35.0) cam_position = math.Vector3(512.0, 500.0, 35.0)
camera_component = ["Camera"] search_filter = entity.SearchFilter()
new_entity_id2 = editor.ToolsApplicationRequestBus( search_filter.names = ["Camera"]
bus.Broadcast, "CreateNewEntityAtPosition", cam_position, EntityId.EntityId() search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
) components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
if new_entity_id2.IsValid():
self.log("Camera entity created")
camera_entity = hydra.Entity("Camera Entity", new_entity_id2)
camera_entity.components = []
for component in camera_component:
camera_entity.components.append(hydra.add_component(component, new_entity_id2))
# 6) Save and export to engine # 6) Save and export to engine
general.save_level() general.save_level()

@ -11,7 +11,8 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import azlmbr.legacy.general as general import azlmbr.legacy.general as general
import azlmbr.asset as asset import azlmbr.asset as asset
import azlmbr.bus as bus import azlmbr.bus as bus
import azlmbr.entity as EntityId import azlmbr.components as components
import azlmbr.entity as entity
import azlmbr.editor as editor import azlmbr.editor as editor
import azlmbr.math as math import azlmbr.math as math
import azlmbr.paths import azlmbr.paths
@ -68,7 +69,7 @@ class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List", veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List",
"Script Canvas"] "Script Canvas"]
new_entity_id = editor.ToolsApplicationRequestBus( new_entity_id = editor.ToolsApplicationRequestBus(
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
) )
if new_entity_id.IsValid(): if new_entity_id.IsValid():
self.log("Spawner entity created") self.log("Spawner entity created")
@ -106,18 +107,12 @@ class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances") self.log(f"Expected {num_expected_instances} instances - Found {num_found} instances")
self.test_success = self.test_success and num_found == num_expected_instances self.test_success = self.test_success and num_found == num_expected_instances
# 5) Create a new entity with a Camera component for testing in the launcher # 5) Move the default Camera entity for testing in the launcher
entity_position = math.Vector3(512.0, 500.0, 35.0) cam_position = math.Vector3(512.0, 500.0, 35.0)
camera_component = ["Camera"] search_filter = entity.SearchFilter()
new_entity_id2 = editor.ToolsApplicationRequestBus( search_filter.names = ["Camera"]
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
) components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
if new_entity_id2.IsValid():
self.log("Camera entity created")
camera_entity = hydra.Entity("Camera Entity", new_entity_id2)
camera_entity.components = []
for component in camera_component:
camera_entity.components.append(hydra.add_component(component, new_entity_id2))
# 6) Save and export to engine # 6) Save and export to engine
general.save_level() general.save_level()

@ -18,9 +18,9 @@ import azlmbr.areasystem as areasystem
import azlmbr.legacy.general as general import azlmbr.legacy.general as general
import azlmbr import azlmbr
import azlmbr.bus as bus import azlmbr.bus as bus
import azlmbr.editor as editor import azlmbr.components as components
import azlmbr.math as math import azlmbr.math as math
import azlmbr.entity as EntityId import azlmbr.entity as entity
import azlmbr.paths import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
@ -134,20 +134,14 @@ class TestVegLayerBlenderCreated(EditorTestHelper):
purple_count += 1 purple_count += 1
self.test_success = pink_count == purple_count and (pink_count + purple_count == num_expected) and self.test_success self.test_success = pink_count == purple_count and (pink_count + purple_count == num_expected) and self.test_success
# 5) Create a new entity with a Camera component for testing in the launcher # 5) Move the default Camera entity for testing in the launcher
entity_position = math.Vector3(500.0, 500.0, 47.0) cam_position = math.Vector3(500.0, 500.0, 47.0)
rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0)) cam_rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
camera_component = ["Camera"] search_filter = entity.SearchFilter()
camera_id = editor.ToolsApplicationRequestBus( search_filter.names = ["Camera"]
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId() search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
) components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
if camera_id.IsValid(): azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector)
self.log("Camera entity created")
camera_entity = hydra.Entity("Camera Entity", camera_id)
camera_entity.components = []
for component in camera_component:
camera_entity.components.append(hydra.add_component(component, camera_id))
azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", camera_id, rot_degrees_vector)
# 6) Save and export level # 6) Save and export level
general.save_level() general.save_level()

@ -34,8 +34,8 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
:return: None :return: None
""" """
PREPROCESS_INSTANCE_COUNT = 425 PREPROCESS_INSTANCE_COUNT = 21
POSTPROCESS_INSTANCE_COUNT = 430 POSTPROCESS_INSTANCE_COUNT = 19
# Create empty level # Create empty level
self.test_success = self.create_level( self.test_success = self.create_level(
@ -56,7 +56,6 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
vegetation_entity.add_component("Vegetation Altitude Filter") vegetation_entity.add_component("Vegetation Altitude Filter")
vegetation_entity.add_component("Vegetation Position Modifier") vegetation_entity.add_component("Vegetation Position Modifier")
# Create a child entity under vegetation area # Create a child entity under vegetation area
child_entity = hydra.Entity("child_entity") child_entity = hydra.Entity("child_entity")
components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"] components_to_add = ["Random Noise Gradient", "Gradient Transform Modifier", "Box Shape"]
@ -66,29 +65,13 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
vegetation_entity.get_set_test(4, "Configuration|Position X|Gradient|Gradient Entity Id", child_entity.id) 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) vegetation_entity.get_set_test(4, "Configuration|Position Y|Gradient|Gradient Entity Id", child_entity.id)
# Set the min and max values for Altitude Filter # Set the min and max values for Altitude Filter
vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 32.0) vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 34.0)
vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 35.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 # 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) 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, 4.0, 4.0) hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0)
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [hill_entity.components[0]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', hill_entity.components[0])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# Set the filter stage to preprocess and postprocess respectively and verify instance count # Set the filter stage to preprocess and postprocess respectively and verify instance count
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1) vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)

@ -13,7 +13,7 @@ import azlmbr.legacy.general as general
import azlmbr.math as math import azlmbr.math as math
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests')) sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper from editor_python_test_tools.editor_test_helper import EditorTestHelper
from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg

@ -82,22 +82,7 @@ class test_MeshBlocker_InstancesBlockedByMesh(EditorTestHelper):
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(), bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
False) False)
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId) blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
components.TransformBus(bus.Event, "SetLocalScale", blocker_entity.id, math.Vector3(2.0, 2.0, 2.0)) components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 2.0)
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# Verify spawned instance counts are accurate after addition of Blocker Entity # 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 num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube

@ -88,24 +88,9 @@ class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(), bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
False) False)
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id) blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
components.TransformBus(bus.Event, "SetLocalScale", blocker_entity.id, math.Vector3(5.0, 5.0, 5.0)) 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)) components.TransformBus(bus.Event, "SetLocalRotation", blocker_entity.id, math.Vector3(0.0, y_rotation, 0.0))
# Disable/Re-enable Mesh component due to ATOM-14299
general.idle_wait(1.0)
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is still enabled")
else:
print("Mesh component was disabled")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [blocker_entity.components[1]])
is_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', blocker_entity.components[1])
if is_enabled:
print("Mesh component is now enabled")
else:
print("Mesh component is still disabled")
# 5) Adjust the height Max percentage values of blocker # 5) Adjust the height Max percentage values of blocker
blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8) blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)

@ -90,7 +90,6 @@ class TestDynamicSliceInstanceSpawner(object):
@pytest.mark.SUITE_periodic @pytest.mark.SUITE_periodic
@pytest.mark.dynveg_area @pytest.mark.dynveg_area
@pytest.mark.parametrize("launcher_platform", ['windows']) @pytest.mark.parametrize("launcher_platform", ['windows'])
@pytest.mark.skip # ATOM-14703
def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level, def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level,
remote_console_instance, project, launcher_platform): remote_console_instance, project, launcher_platform):
@ -126,7 +125,6 @@ class TestDynamicSliceInstanceSpawner(object):
@pytest.mark.SUITE_periodic @pytest.mark.SUITE_periodic
@pytest.mark.dynveg_area @pytest.mark.dynveg_area
@pytest.mark.parametrize("launcher_platform", ['windows']) @pytest.mark.parametrize("launcher_platform", ['windows'])
@pytest.mark.skip # ATOM-14703
def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level, def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level,
remote_console_instance, project, launcher_platform): remote_console_instance, project, launcher_platform):

@ -68,7 +68,6 @@ class TestLayerBlender(object):
"Entity has a Box Shape component", "Entity has a Box Shape component",
"Blender Configuration|Vegetation Areas: SUCCESS", "Blender Configuration|Vegetation Areas: SUCCESS",
"Blender Box Shape|Box Configuration|Dimensions: SUCCESS", "Blender Box Shape|Box Configuration|Dimensions: SUCCESS",
"Camera entity created",
"LayerBlender_E2E_Editor: result=SUCCESS" "LayerBlender_E2E_Editor: result=SUCCESS"
] ]
@ -85,12 +84,11 @@ class TestLayerBlender(object):
@pytest.mark.BAT @pytest.mark.BAT
@pytest.mark.SUITE_periodic @pytest.mark.SUITE_periodic
@pytest.mark.dynveg_area @pytest.mark.dynveg_area
@pytest.mark.xfail
@pytest.mark.parametrize("launcher_platform", ['windows']) @pytest.mark.parametrize("launcher_platform", ['windows'])
def test_LayerBlender_E2E_Launcher(self, workspace, project, launcher, level, remote_console_instance, def test_LayerBlender_E2E_Launcher(self, workspace, project, launcher, level, remote_console_instance,
launcher_platform): launcher_platform):
launcher.args.extend(["-NullRenderer"]) launcher.args.extend(["-rhi=Null"])
launcher.start() launcher.start()
assert launcher.is_alive(), "Launcher failed to start" assert launcher.is_alive(), "Launcher failed to start"

@ -121,7 +121,7 @@ class TestLayerSpawner(object):
@pytest.mark.test_case_id("C30000751") @pytest.mark.test_case_id("C30000751")
@pytest.mark.SUITE_sandbox @pytest.mark.SUITE_sandbox
@pytest.mark.dynveg_misc @pytest.mark.dynveg_misc
@pytest.mark.skip # ATOM-14828 @pytest.mark.skip # https://github.com/o3de/o3de/issues/2038
def test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(self, request, editor, level, launcher_platform): def test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(self, request, editor, level, launcher_platform):
expected_lines = [ expected_lines = [
@ -136,5 +136,6 @@ class TestLayerSpawner(object):
editor, editor,
"LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py", "LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py",
expected_lines, expected_lines,
cfg_args=[level] cfg_args=[level],
null_renderer=False
) )

@ -34,7 +34,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z
return surface_entity return surface_entity
def create_mesh_surface_entity_with_slopes(name, center_point, scale_x, scale_y, scale_z): def create_mesh_surface_entity_with_slopes(name, center_point, uniform_scale):
# Creates an entity with the assigned mesh_asset as the specified scale and sets up as a planting surface # Creates an entity with the assigned mesh_asset as the specified scale and sets up as a planting surface
mesh_asset_path = os.path.join("models", "sphere.azmodel") mesh_asset_path = os.path.join("models", "sphere.azmodel")
mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(), mesh_asset = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", mesh_asset_path, math.Uuid(),
@ -47,7 +47,7 @@ def create_mesh_surface_entity_with_slopes(name, center_point, scale_x, scale_y,
if surface_entity.id.IsValid(): if surface_entity.id.IsValid():
print(f"'{surface_entity.name}' created") print(f"'{surface_entity.name}' created")
hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset) hydra.get_set_test(surface_entity, 0, "Controller|Configuration|Mesh Asset", mesh_asset)
components.TransformBus(bus.Event, "SetLocalScale", surface_entity.id, math.Vector3(scale_x, scale_y, scale_z)) components.TransformBus(bus.Event, "SetLocalUniformScale", surface_entity.id, uniform_scale)
return surface_entity return surface_entity

@ -5,6 +5,13 @@
# #
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
include(${LY_ROOT_FOLDER}/Code/Tools/SerializeContextTools/Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
if (PAL_TRAIT_BUILD_SERIALIZECONTEXTTOOLS)
list(APPEND additional_dependencies AZ::SerializeContextTools) # test_CLITool_SerializeContextTools depends on it
endif()
list(APPEND additional_dependencies AZ::AssetBundlerBatch) # test_CLITool_AssetBundlerBatch_Works depends on it
ly_add_pytest( ly_add_pytest(
NAME AutomatedTesting::SmokeTest NAME AutomatedTesting::SmokeTest
TEST_SUITE smoke TEST_SUITE smoke
@ -18,6 +25,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
Legacy::Editor Legacy::Editor
AutomatedTesting.GameLauncher AutomatedTesting.GameLauncher
AutomatedTesting.Assets AutomatedTesting.Assets
${aditional_dependencies}
COMPONENT COMPONENT
Smoke Smoke
) )

@ -742,14 +742,14 @@
</Class> </Class>
<Class name="int" field="methodType" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/> <Class name="int" field="methodType" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
<Class name="AZStd::string" field="methodName" value="GetOnPostsimulateEvent" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="methodName" value="GetOnPostsimulateEvent" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::string" field="className" value="System Interface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="className" value="PhysicsSystemInterface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::vector" field="namespaces" type="{99DAD0BC-740E-5E82-826B-8FC7968CC02C}"/> <Class name="AZStd::vector" field="namespaces" type="{99DAD0BC-740E-5E82-826B-8FC7968CC02C}"/>
<Class name="AZStd::vector" field="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}"> <Class name="AZStd::vector" field="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}">
<Class name="SlotId" field="element" version="2" type="{14C629F6-467B-46FE-8B63-48FDFCA42175}"> <Class name="SlotId" field="element" version="2" type="{14C629F6-467B-46FE-8B63-48FDFCA42175}">
<Class name="AZ::Uuid" field="m_id" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/> <Class name="AZ::Uuid" field="m_id" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
</Class> </Class>
</Class> </Class>
<Class name="AZStd::string" field="prettyClassName" value="System Interface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="prettyClassName" value="PhysicsSystemInterface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class> </Class>
</Class> </Class>
<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/> <Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>

@ -1045,14 +1045,14 @@
</Class> </Class>
<Class name="int" field="methodType" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/> <Class name="int" field="methodType" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
<Class name="AZStd::string" field="methodName" value="GetOnPostsimulateEvent" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="methodName" value="GetOnPostsimulateEvent" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::string" field="className" value="System Interface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="className" value="PhysicsSystemInterface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::vector" field="namespaces" type="{99DAD0BC-740E-5E82-826B-8FC7968CC02C}"/> <Class name="AZStd::vector" field="namespaces" type="{99DAD0BC-740E-5E82-826B-8FC7968CC02C}"/>
<Class name="AZStd::vector" field="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}"> <Class name="AZStd::vector" field="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}">
<Class name="SlotId" field="element" version="2" type="{14C629F6-467B-46FE-8B63-48FDFCA42175}"> <Class name="SlotId" field="element" version="2" type="{14C629F6-467B-46FE-8B63-48FDFCA42175}">
<Class name="AZ::Uuid" field="m_id" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/> <Class name="AZ::Uuid" field="m_id" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
</Class> </Class>
</Class> </Class>
<Class name="AZStd::string" field="prettyClassName" value="System Interface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="prettyClassName" value="PhysicsSystemInterface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class> </Class>
</Class> </Class>
<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/> <Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>

@ -1085,14 +1085,14 @@
</Class> </Class>
<Class name="int" field="methodType" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/> <Class name="int" field="methodType" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
<Class name="AZStd::string" field="methodName" value="GetOnPresimulateEvent" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="methodName" value="GetOnPresimulateEvent" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::string" field="className" value="System Interface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="className" value="PhysicsSystemInterface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="AZStd::vector" field="namespaces" type="{99DAD0BC-740E-5E82-826B-8FC7968CC02C}"/> <Class name="AZStd::vector" field="namespaces" type="{99DAD0BC-740E-5E82-826B-8FC7968CC02C}"/>
<Class name="AZStd::vector" field="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}"> <Class name="AZStd::vector" field="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}">
<Class name="SlotId" field="element" version="2" type="{14C629F6-467B-46FE-8B63-48FDFCA42175}"> <Class name="SlotId" field="element" version="2" type="{14C629F6-467B-46FE-8B63-48FDFCA42175}">
<Class name="AZ::Uuid" field="m_id" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/> <Class name="AZ::Uuid" field="m_id" value="{00000000-0000-0000-0000-000000000000}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
</Class> </Class>
</Class> </Class>
<Class name="AZStd::string" field="prettyClassName" value="System Interface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/> <Class name="AZStd::string" field="prettyClassName" value="PhysicsSystemInterface" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class> </Class>
</Class> </Class>
<Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/> <Class name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>

@ -497,9 +497,15 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe
// Hide Selection // Hide Selection
editMenu.AddAction(AzToolsFramework::HideSelection); editMenu.AddAction(AzToolsFramework::HideSelection);
// Unhide All // Show All
editMenu.AddAction(AzToolsFramework::ShowAll); editMenu.AddAction(AzToolsFramework::ShowAll);
// Lock Selection
editMenu.AddAction(AzToolsFramework::LockSelection);
// UnLock All
editMenu.AddAction(AzToolsFramework::UnlockAll);
/* /*
* The following block of code is part of the feature "Isolation Mode" and is temporarily * The following block of code is part of the feature "Isolation Mode" and is temporarily
* disabled for 1.10 release. * disabled for 1.10 release.

@ -1896,7 +1896,7 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame) if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame)
{ {
CUndo undo("Move Camera"); AzToolsFramework::ScopedUndoBatch undo("Move Camera");
if (bMoveOnly) if (bMoveOnly)
{ {
// specify eObjectUpdateFlags_UserInput so that an undo command gets logged // specify eObjectUpdateFlags_UserInput so that an undo command gets logged
@ -1932,7 +1932,7 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame) if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame)
{ {
CUndo undo("Move Camera"); AzToolsFramework::ScopedUndoBatch undo("Move Camera");
if (bMoveOnly) if (bMoveOnly)
{ {
AZ::TransformBus::Event( AZ::TransformBus::Event(
@ -1945,6 +1945,8 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
m_viewEntityId, &AZ::TransformInterface::SetWorldTM, m_viewEntityId, &AZ::TransformInterface::SetWorldTM,
LYTransformToAZTransform(camMatrix)); LYTransformToAZTransform(camMatrix));
} }
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::AddDirtyEntity, m_viewEntityId);
} }
else else
{ {

@ -83,9 +83,9 @@ AZ::RPI::ViewportContextPtr LegacyViewportCameraControllerInstance::GetViewportC
} }
bool LegacyViewportCameraControllerInstance::HandleMouseMove( bool LegacyViewportCameraControllerInstance::HandleMouseMove(
const AzFramework::ScreenPoint& currentMousePos, const AzFramework::ScreenPoint& previousMousePos) int dx, int dy)
{ {
if (previousMousePos == currentMousePos) if (dx == 0 && dy == 0)
{ {
return false; return false;
} }
@ -105,7 +105,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(
if (m_inMoveMode || m_inOrbitMode || m_inRotateMode || m_inZoomMode) if (m_inMoveMode || m_inOrbitMode || m_inRotateMode || m_inZoomMode)
{ {
m_totalMouseMoveDelta += (QPoint(currentMousePos.m_x, currentMousePos.m_y)-QPoint(previousMousePos.m_x, previousMousePos.m_y)).manhattanLength(); m_totalMouseMoveDelta += AZStd::abs(dx) + AZStd::abs(dy);
} }
if ((m_inRotateMode && m_inMoveMode) || m_inZoomMode) if ((m_inRotateMode && m_inMoveMode) || m_inZoomMode)
@ -115,7 +115,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(
Vec3 ydir = m.GetColumn1().GetNormalized(); Vec3 ydir = m.GetColumn1().GetNormalized();
Vec3 pos = m.GetTranslation(); Vec3 pos = m.GetTranslation();
const float posDelta = 0.2f * (previousMousePos.m_y - currentMousePos.m_y) * speedScale; const float posDelta = 0.2f * dy * speedScale;
pos = pos - ydir * posDelta; pos = pos - ydir * posDelta;
m_orbitDistance = m_orbitDistance + posDelta; m_orbitDistance = m_orbitDistance + posDelta;
m_orbitDistance = fabs(m_orbitDistance); m_orbitDistance = fabs(m_orbitDistance);
@ -126,7 +126,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(
} }
else if (m_inRotateMode) else if (m_inRotateMode)
{ {
Ang3 angles(-currentMousePos.m_y + previousMousePos.m_y, 0, -currentMousePos.m_x + previousMousePos.m_x); Ang3 angles(dy, 0, dx);
angles = angles * 0.002f * gSettings.cameraRotateSpeed; angles = angles * 0.002f * gSettings.cameraRotateSpeed;
if (gSettings.invertYRotation) if (gSettings.invertYRotation)
{ {
@ -158,7 +158,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(
} }
Vec3 pos = m.GetTranslation(); Vec3 pos = m.GetTranslation();
pos += 0.1f * xdir * (currentMousePos.m_x - previousMousePos.m_x) * speedScale + 0.1f * zdir * (previousMousePos.m_y - currentMousePos.m_y) * speedScale; pos += 0.1f * xdir * dx * speedScale + 0.1f * zdir * dy * speedScale;
m.SetTranslation(pos); m.SetTranslation(pos);
AZ::Transform transform = viewportContext->GetCameraTransform(); AZ::Transform transform = viewportContext->GetCameraTransform();
@ -168,7 +168,7 @@ bool LegacyViewportCameraControllerInstance::HandleMouseMove(
} }
else if (m_inOrbitMode) else if (m_inOrbitMode)
{ {
Ang3 angles(-currentMousePos.m_y + previousMousePos.m_y, 0, -currentMousePos.m_x + previousMousePos.m_x); Ang3 angles(dy, 0, dx);
angles = angles * 0.002f * gSettings.cameraRotateSpeed; angles = angles * 0.002f * gSettings.cameraRotateSpeed;
if (gSettings.invertPan) if (gSettings.invertPan)
@ -302,20 +302,19 @@ bool LegacyViewportCameraControllerInstance::HandleInputChannelEvent(const AzFra
bool shouldCaptureCursor = m_capturingCursor; bool shouldCaptureCursor = m_capturingCursor;
bool shouldConsumeEvent = false; bool shouldConsumeEvent = false;
if (id == AzFramework::InputDeviceMouse::SystemCursorPosition) if (id == AzFramework::InputDeviceMouse::Movement::X || id == AzFramework::InputDeviceMouse::Movement::Y)
{ {
bool result = false; int dx = 0;
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event( int dy = 0;
GetViewportId(), if (id == AzFramework::InputDeviceMouse::Movement::X)
[this, &result](AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequests* mouseRequests)
{ {
if (auto previousMousePosition = mouseRequests->PreviousViewportCursorScreenPosition(); dx = -aznumeric_cast<int>(event.m_inputChannel.GetValue());
previousMousePosition.has_value()) }
else
{ {
result = HandleMouseMove(mouseRequests->ViewportCursorScreenPosition(), previousMousePosition.value()); dy = -aznumeric_cast<int>(event.m_inputChannel.GetValue());
} }
}); return HandleMouseMove(dx, dy);
return result;
} }
else if (id == MouseButton::Left) else if (id == MouseButton::Left)
{ {

@ -69,7 +69,7 @@ namespace SandboxEditor
AZ::RPI::ViewportContextPtr GetViewportContext(); AZ::RPI::ViewportContextPtr GetViewportContext();
bool HandleMouseMove(const AzFramework::ScreenPoint& currentMousePos, const AzFramework::ScreenPoint& previousMousePos); bool HandleMouseMove(int dx, int dy);
bool HandleMouseWheel(float zDelta); bool HandleMouseWheel(float zDelta);
bool IsKeyDown(Qt::Key key) const; bool IsKeyDown(Qt::Key key) const;
void UpdateCursorCapture(bool shouldCaptureCursor); void UpdateCursorCapture(bool shouldCaptureCursor);

@ -5,7 +5,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>Editor</string> <string>Editor</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>com.Amazon.Lumberyard.Editor</string> <string>org.O3DE.Editor</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>

@ -46,4 +46,8 @@ ly_add_target(
AZ::AzCore AZ::AzCore
AZ::AzToolsFramework AZ::AzToolsFramework
AZ::AzQtComponents AZ::AzQtComponents
RUNTIME_DEPENDENCIES
AZ::AzCore
AZ::AzToolsFramework
AZ::AzQtComponents
) )

@ -20,12 +20,12 @@
#include "ValidationHandler.h" #include "ValidationHandler.h"
#include <AzCore/Component/ComponentApplicationBus.h> #include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/IO/Path/Path.h>
#include "AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h" #include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
#include <AzToolsFramework/UI/PropertyEditor/PropertyManagerComponent.h> #include <AzToolsFramework/UI/PropertyEditor/PropertyManagerComponent.h>
#include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx> #include <AzToolsFramework/UI/PropertyEditor/ReflectedPropertyEditor.hxx>
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h> #include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
#include <Util/FileUtil.h>
#include <QMessageBox> #include <QMessageBox>
#include <QCloseEvent> #include <QCloseEvent>
@ -52,7 +52,7 @@ namespace ProjectSettingsTool
PlatformEnabled(PlatformId::Ios) ? PlatformEnabled(PlatformId::Ios) ?
ProjectSettingsContainer::PlistInitVector({ ProjectSettingsContainer::PlistInitVector({
ProjectSettingsContainer::PlatformAndPath ProjectSettingsContainer::PlatformAndPath
{ PlatformId::Ios, m_projectRoot + PlatformResourcesFolder(PlatformId::Ios) } { PlatformId::Ios, GetPlatformResource(PlatformId::Ios) }
}) })
: :
ProjectSettingsContainer::PlistInitVector()) ProjectSettingsContainer::PlistInitVector())
@ -647,33 +647,38 @@ namespace ProjectSettingsTool
// iOS can be disabled if the plist file is missing // iOS can be disabled if the plist file is missing
if (platformId == PlatformId::Ios) if (platformId == PlatformId::Ios)
{ {
const AZStd::string filename = m_projectRoot + PlatformResourcesFolder(platformId); AZStd::string plistPath = GetPlatformResource(platformId);
return CFileUtil::FileExists(filename.c_str()); return !plistPath.empty();
} }
return true; return true;
} }
const char* ProjectSettingsToolWindow::PlatformResourcesFolder(PlatformId platformId) AZStd::string ProjectSettingsToolWindow::GetPlatformResource(PlatformId platformId)
{ {
if (platformId == PlatformId::Ios) if (platformId == PlatformId::Ios)
{ {
const AZStd::string firstfilename = m_projectRoot + "/Gem/Resources/Platform/iOS/Info.plist"; const char* searchPaths[] = {
if (CFileUtil::FileExists(firstfilename.c_str())) "Resources/Platform/iOS/Info.plist",
{
return "/Gem/Resources/Platform/iOS/Info.plist"; // legacy paths
} "Gem/Resources/Platform/iOS/Info.plist",
else "Gem/Resources/IOSLauncher/Info.plist",
};
for (auto relPath : searchPaths)
{ {
const AZStd::string filename = m_projectRoot + "/Gem/Resources/IOSLauncher/Info.plist"; AZ::IO::FixedMaxPath projectPlist{ m_projectRoot };
if (CFileUtil::FileExists(filename.c_str())) projectPlist /= relPath;
if (AZ::IO::SystemFile::Exists(projectPlist.c_str()))
{ {
return "/Gem/Resources/IOSLauncher/Info.plist"; return projectPlist.LexicallyNormal().String();
} }
} }
} }
return nullptr; return AZStd::string();
} }
#include <moc_ProjectSettingsToolWindow.cpp> #include <moc_ProjectSettingsToolWindow.cpp>

@ -137,8 +137,8 @@ namespace ProjectSettingsTool
// returns true if the platform is enabled // returns true if the platform is enabled
bool PlatformEnabled(PlatformId platformId); bool PlatformEnabled(PlatformId platformId);
// returns the resource folder // returns the main platform specific resource file e.g. for iOS it would be the Info.plist
const char* PlatformResourcesFolder(PlatformId platformId); AZStd::string GetPlatformResource(PlatformId platformId);
// The ui for the window // The ui for the window
QScopedPointer<Ui::ProjectSettingsToolWidget> m_ui; QScopedPointer<Ui::ProjectSettingsToolWidget> m_ui;

@ -116,7 +116,7 @@ namespace AZ
{ {
const char* uuidString = nullptr; const char* uuidString = nullptr;
unsigned int uuidStringLength = 0; unsigned int uuidStringLength = 0;
if (dc.ReadArg(0, uuidString) && dc.ReadValue(1, uuidStringLength)) if (dc.ReadArg(0, uuidString) && dc.ReadArg(1, uuidStringLength))
{ {
dc.PushResult(Uuid(uuidString, uuidStringLength)); dc.PushResult(Uuid(uuidString, uuidStringLength));
} }

@ -157,8 +157,11 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
lua_pop(l, 2); // pop the Class name and behaviorClass lua_pop(l, 2); // pop the Class name and behaviorClass
lua_pushnil(l); lua_pushnil(l);
// iterate over the key/value pairs
while (lua_next(l, -2) != 0) while (lua_next(l, -2) != 0)
{ {
// if key: string value: function
if (lua_isstring(l, -2) && lua_isfunction(l, -1)) if (lua_isstring(l, -2) && lua_isfunction(l, -1))
{ {
const char* name = lua_tostring(l, -2); const char* name = lua_tostring(l, -2);
@ -167,6 +170,7 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
bool isRead = true; bool isRead = true;
bool isWrite = true; bool isWrite = true;
// check if there is a getter provided
lua_getupvalue(l, -1, 1); lua_getupvalue(l, -1, 1);
if (lua_isnil(l, -1)) if (lua_isnil(l, -1))
{ {
@ -174,6 +178,7 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
} }
lua_pop(l, 1); lua_pop(l, 1);
// check if there is a setter provided
lua_getupvalue(l, -1, 2); lua_getupvalue(l, -1, 2);
if (lua_isnil(l, -1)) if (lua_isnil(l, -1))
{ {
@ -181,6 +186,7 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
} }
lua_pop(l, 1); lua_pop(l, 1);
// enumerate the remaining property
if (!enumProperty(&behaviorClass->m_typeId, name, isRead, isWrite, userData)) if (!enumProperty(&behaviorClass->m_typeId, name, isRead, isWrite, userData))
{ {
lua_pop(l, 5); lua_pop(l, 5);
@ -189,21 +195,30 @@ ScriptContextDebug::EnumRegisteredClasses(EnumClass enumClass, EnumMethod enumMe
} }
else else
{ {
// for any non-built in methods
if (strncmp(name, "__", 2) != 0) if (strncmp(name, "__", 2) != 0)
{ {
const char* dbgParamInfo = NULL; const char* dbgParamInfo = NULL;
lua_getupvalue(l, -1, 2);
// attempt to get the name
bool popDebugName = lua_getupvalue(l, -1, 2) != nullptr;
if (lua_isstring(l, -1)) if (lua_isstring(l, -1))
{ {
dbgParamInfo = lua_tostring(l, -1); dbgParamInfo = lua_tostring(l, -1);
} }
// enumerate the method's parameters
if (!enumMethod(&behaviorClass->m_typeId, name, dbgParamInfo, userData)) if (!enumMethod(&behaviorClass->m_typeId, name, dbgParamInfo, userData))
{ {
lua_pop(l, 6); lua_pop(l, 6);
return; return;
} }
lua_pop(l, 1); // pop the DBG name
// if we were able to get the name, pop it from the stack
if (popDebugName)
{
lua_pop(l, 1);
}
} }
} }
} }

@ -7,9 +7,9 @@
*/ */
#include <AZTestShared/Utils/Utils.h> #include <AZTestShared/Utils/Utils.h>
#include "AzCore/Component/Entity.h" #include <AzCore/Component/Entity.h>
#include "AzCore/Asset/AssetManager.h" #include <AzCore/Asset/AssetManager.h>
#include "AzCore/Slice/SliceComponent.h" #include <AzCore/Slice/SliceComponent.h>
namespace UnitTest namespace UnitTest
{ {

@ -6,6 +6,7 @@
*/ */
#include <AzCore/Math/Vector3.h> #include <AzCore/Math/Vector3.h>
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
#include <AzCore/std/string/string_view.h> #include <AzCore/std/string/string_view.h>
#include <Tests/Serialization/Json/JsonSerializationTests.h> #include <Tests/Serialization/Json/JsonSerializationTests.h>
@ -43,7 +44,9 @@ namespace JsonSerializationTests
} }
void CheckApplyPatchOutcome(const char* target, const char* patch, void CheckApplyPatchOutcome(const char* target, const char* patch,
AZ::JsonSerializationResult::Outcomes outcome, AZ::JsonSerializationResult::Processing processing) AZ::JsonSerializationResult::Outcomes outcome,
AZ::JsonSerializationResult::Processing processing,
const AZ::JsonApplyPatchSettings& settings = AZ::JsonApplyPatchSettings{})
{ {
m_jsonDocument->Parse(target); m_jsonDocument->Parse(target);
ASSERT_FALSE(m_jsonDocument->HasParseError()); ASSERT_FALSE(m_jsonDocument->HasParseError());
@ -53,12 +56,24 @@ namespace JsonSerializationTests
ASSERT_FALSE(patchDocument.HasParseError()); ASSERT_FALSE(patchDocument.HasParseError());
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(*m_jsonDocument, AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(*m_jsonDocument,
m_jsonDocument->GetAllocator(), patchDocument, AZ::JsonMergeApproach::JsonPatch); m_jsonDocument->GetAllocator(), patchDocument, AZ::JsonMergeApproach::JsonPatch, settings);
EXPECT_EQ(result.GetTask(), AZ::JsonSerializationResult::Tasks::Merge); EXPECT_EQ(result.GetTask(), AZ::JsonSerializationResult::Tasks::Merge);
EXPECT_EQ(result.GetOutcome(), outcome); EXPECT_EQ(result.GetOutcome(), outcome);
EXPECT_EQ(result.GetProcessing(), processing); EXPECT_EQ(result.GetProcessing(), processing);
} }
void CheckApplyPatchOutcome(
const char* target,
const char* patch,
const char* expectedPatchedResult,
AZ::JsonSerializationResult::Outcomes outcome,
AZ::JsonSerializationResult::Processing processing,
const AZ::JsonApplyPatchSettings& settings = AZ::JsonApplyPatchSettings{})
{
CheckApplyPatchOutcome(target, patch, outcome, processing, settings);
Expect_DocStrEq(expectedPatchedResult);
}
void CheckCreatePatch_Core(const char* source, AZStd::string_view patch, const char* target, void CheckCreatePatch_Core(const char* source, AZStd::string_view patch, const char* target,
AZ::JsonMergeApproach approach) AZ::JsonMergeApproach approach)
{ {
@ -262,6 +277,36 @@ namespace JsonSerializationTests
Outcomes::TypeMismatch, Processing::Halted); Outcomes::TypeMismatch, Processing::Halted);
} }
TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchWithCustomReportingCallback_ReportPartialSkip)
{
using namespace AZ::JsonSerializationResult;
auto issueReportingCallback = [](AZStd::string_view, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view) -> AZ::JsonSerializationResult::ResultCode
{
using namespace AZ::JsonSerializationResult;
if (result.GetProcessing() == Processing::Halted)
{
return ResultCode(result.GetTask(), Outcomes::PartialSkip);
}
return result;
};
AZ::JsonApplyPatchSettings applyPatchSettings;
applyPatchSettings.m_reporting = AZStd::move(issueReportingCallback);
CheckApplyPatchOutcome(
R"({})",
R"([
{ "op": "add", "path": "/nonexistent_key/new_member", "value": "someValue" },
{ "op": "add", "path": "/test", "value": "someValue" }
])",
R"(
{ "test": "someValue" }
)",
Outcomes::PartialSkip,
Processing::Completed,
AZStd::move(applyPatchSettings));
}
TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchAddUnnamedMember_ReportsSuccess) TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchAddUnnamedMember_ReportsSuccess)
{ {
CheckApplyPatch( CheckApplyPatch(

@ -279,14 +279,11 @@ namespace AZ
return SystemFile::Exists(resolvedPath); return SystemFile::Exists(resolvedPath);
} }
void LocalFileIO::CheckInvalidWrite(const char* path) void LocalFileIO::CheckInvalidWrite([[maybe_unused]] const char* path)
{ {
(void)path;
#if defined(AZ_ENABLE_TRACING) #if defined(AZ_ENABLE_TRACING)
const char* assetsAlias = GetAlias("@assets@"); const char* assetsAlias = GetAlias("@assets@");
if (path && assetsAlias && AZ::IO::PathView(path).IsRelativeTo(assetsAlias))
if (((path) && (assetsAlias) && (azstrnicmp(path, assetsAlias, strlen(assetsAlias)) == 0)))
{ {
AZ_Error("FileIO", false, "You may not alter data inside the asset cache. Please check the call stack and consider writing into the source asset folder instead.\n" AZ_Error("FileIO", false, "You may not alter data inside the asset cache. Please check the call stack and consider writing into the source asset folder instead.\n"
"Attempted write location: %s", path); "Attempted write location: %s", path);

@ -205,6 +205,25 @@ namespace AzFramework
class InputDeviceImplementationRequest : public AZ::EBusTraits class InputDeviceImplementationRequest : public AZ::EBusTraits
{ {
public: public:
////////////////////////////////////////////////////////////////////////////////////////////
//! EBus Trait: requests can be addressed to a specific InputDeviceId so that they are only
//! handled by one input device that has connected to the bus using that unique id, or they
//! can be broadcast to all input devices that have connected to the bus, regardless of id.
//! Connected input devices are ordered by their local player index from lowest to highest.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ByIdAndOrdered;
////////////////////////////////////////////////////////////////////////////////////////////
//! EBus Trait: requests should be handled by only one input device connected to each id
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
////////////////////////////////////////////////////////////////////////////////////////////
//! EBus Trait: requests can be addressed to a specific InputDeviceId
using BusIdType = InputDeviceId;
////////////////////////////////////////////////////////////////////////////////////////////
//! EBus Trait: requests are handled by connected devices in the order of local player index
using BusIdOrderCompare = AZStd::less<BusIdType>;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! Alias for the EBus implementation of this interface //! Alias for the EBus implementation of this interface
using Bus = AZ::EBus<InputDeviceImplementationRequest<InputDeviceType>>; using Bus = AZ::EBus<InputDeviceImplementationRequest<InputDeviceType>>;
@ -214,11 +233,12 @@ namespace AzFramework
using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&); using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! Create a custom implementation for all the existing instances of this input device type. //! Set a custom implementation for this input device type, either for a specific instance
//! by addressing the call to an InputDeviceId, or for all existing instances by broadcast.
//! Passing InputDeviceType::Implementation::Create as the argument will create the default //! Passing InputDeviceType::Implementation::Create as the argument will create the default
//! device implementation, while passing nullptr will delete any existing implementation. //! device implementation, while passing nullptr will delete any existing implementation.
//! \param[in] createFunction Pointer to the function that will create the implementation. //! \param[in] createFunction Pointer to the function that will create the implementation.
virtual void CreateCustomImplementation(CreateFunctionType createFunction) = 0; virtual void SetCustomImplementation(CreateFunctionType createFunction) = 0;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
@ -238,7 +258,7 @@ namespace AzFramework
AZ_INLINE InputDeviceImplementationRequestHandler(InputDeviceType& inputDevice) AZ_INLINE InputDeviceImplementationRequestHandler(InputDeviceType& inputDevice)
: m_inputDevice(inputDevice) : m_inputDevice(inputDevice)
{ {
InputDeviceImplementationRequest<InputDeviceType>::Bus::Handler::BusConnect(); InputDeviceImplementationRequest<InputDeviceType>::Bus::Handler::BusConnect(m_inputDevice.GetInputDeviceId());
} }
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@ -251,8 +271,8 @@ namespace AzFramework
using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&); using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! \ref InputDeviceImplementationRequest<InputDeviceType>::CreateCustomImplementation //! \ref InputDeviceImplementationRequest<InputDeviceType>::SetCustomImplementation
AZ_INLINE void CreateCustomImplementation(CreateFunctionType createFunction) override AZ_INLINE void SetCustomImplementation(CreateFunctionType createFunction) override
{ {
AZStd::unique_ptr<typename InputDeviceType::Implementation> newImplementation; AZStd::unique_ptr<typename InputDeviceType::Implementation> newImplementation;
if (createFunction) if (createFunction)

@ -97,6 +97,9 @@ namespace AzFramework
//! This is called when the window is deactivated from code or if the user closes the window. //! This is called when the window is deactivated from code or if the user closes the window.
virtual void OnWindowClosed() {}; virtual void OnWindowClosed() {};
//! This is called when vsync interval is changed.
virtual void OnVsyncIntervalChanged(uint32_t interval) { AZ_UNUSED(interval); };
}; };
using WindowNotificationBus = AZ::EBus<WindowNotifications>; using WindowNotificationBus = AZ::EBus<WindowNotifications>;

@ -52,3 +52,63 @@ ly_add_source_properties(
PROPERTY COMPILE_DEFINITIONS PROPERTY COMPILE_DEFINITIONS
VALUES TOUCHBENDING_LAYER_BIT=${LY_TOUCHBENDING_LAYER_BIT} VALUES TOUCHBENDING_LAYER_BIT=${LY_TOUCHBENDING_LAYER_BIT}
) )
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Tests/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AzFrameworkTestShared STATIC
NAMESPACE AZ
FILES_CMAKE
Tests/framework_shared_tests_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
)
if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME ProcessLaunchTest EXECUTABLE
NAMESPACE AZ
FILES_CMAKE
Tests/process_launch_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzFramework
)
ly_add_target(
NAME AzFramework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
Tests/frameworktests_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
${pal_dir}
BUILD_DEPENDENCIES
PRIVATE
AZ::AzFramework
AZ::AzTest
AZ::AzTestShared
AZ::AzFrameworkTestShared
RUNTIME_DEPENDENCIES
AZ::ProcessLaunchTest
)
ly_add_googletest(
NAME AZ::AzFramework.Tests
)
endif()
endif()

@ -15,16 +15,16 @@ namespace UnitTest
{ {
using namespace AZ; using namespace AZ;
class SetRestoreFileIOBaseRAII class FileIOBaseRAII
{ {
public: public:
SetRestoreFileIOBaseRAII(AZ::IO::FileIOBase& fileIO) FileIOBaseRAII(AZ::IO::FileIOBase& fileIO)
: m_prevFileIO(AZ::IO::FileIOBase::GetInstance()) : m_prevFileIO(AZ::IO::FileIOBase::GetInstance())
{ {
AZ::IO::FileIOBase::SetInstance(&fileIO); AZ::IO::FileIOBase::SetInstance(&fileIO);
} }
~SetRestoreFileIOBaseRAII() ~FileIOBaseRAII()
{ {
AZ::IO::FileIOBase::SetInstance(m_prevFileIO); AZ::IO::FileIOBase::SetInstance(m_prevFileIO);
} }
@ -102,7 +102,7 @@ namespace UnitTest
TEST_F(GenAppDescriptors, Test) TEST_F(GenAppDescriptors, Test)
{ {
AZ::IO::LocalFileIO fileIO; AZ::IO::LocalFileIO fileIO;
SetRestoreFileIOBaseRAII restoreFileIOScope(fileIO); FileIOBaseRAII restoreFileIOScope(fileIO);
run(); run();
} }
} }

@ -9,7 +9,6 @@
AZ_PUSH_DISABLE_WARNING(, "-Wdelete-non-virtual-dtor") AZ_PUSH_DISABLE_WARNING(, "-Wdelete-non-virtual-dtor")
#include <FrameworkApplicationFixture.h>
#include <AzCore/Component/ComponentApplication.h> #include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Component/Entity.h> #include <AzCore/Component/Entity.h>
#include <AzCore/Component/Component.h> #include <AzCore/Component/Component.h>

@ -9,4 +9,5 @@ set(FILES
Mocks/MockSpawnableEntitiesInterface.h Mocks/MockSpawnableEntitiesInterface.h
Utils/Utils.h Utils/Utils.h
Utils/Utils.cpp Utils/Utils.cpp
FrameworkApplicationFixture.h
) )

@ -6,44 +6,28 @@
# #
set(FILES set(FILES
../AzCore/Tests/Main.cpp ../../AzCore/Tests/Main.cpp
Spawnable/SpawnableEntitiesManagerTests.cpp Spawnable/SpawnableEntitiesManagerTests.cpp
ArchiveCompressionTests.cpp ArchiveCompressionTests.cpp
ArchiveTests.cpp ArchiveTests.cpp
BehaviorEntityTests.cpp BehaviorEntityTests.cpp
BinToTextEncode.cpp BinToTextEncode.cpp
ComponentAddRemove.cpp
ComponentAdapterTests.cpp
CameraInputTests.cpp CameraInputTests.cpp
ClickDetectorTests.cpp ClickDetectorTests.cpp
CursorStateTests.cpp CursorStateTests.cpp
EntityContext.cpp EntityContext.cpp
EntityTestbed.h
FileFunc.cpp
FileIO.cpp FileIO.cpp
FileTagTests.cpp FileTagTests.cpp
FrameworkApplicationFixture.h
GenAppDescriptors.cpp GenAppDescriptors.cpp
GenericComponentWrapperTest.cpp
InstanceDataHierarchy.cpp
OctreePerformanceTests.cpp OctreePerformanceTests.cpp
OctreeTests.cpp OctreeTests.cpp
Slices.cpp
Script/ScriptComponentTests.cpp
Script/ScriptEntityTests.cpp
AssetCatalog.cpp AssetCatalog.cpp
AssetProcessorConnection.cpp AssetProcessorConnection.cpp
NativeWindow.cpp NativeWindow.cpp
TransformComponent.cpp
SQLiteConnectionTests.cpp
ProcessLaunchParseTests.cpp ProcessLaunchParseTests.cpp
Application.cpp Application.cpp
PlatformHelper.cpp PlatformHelper.cpp
Scene.cpp Scene.cpp
EntityOwnershipService/EntityOwnershipServiceTestFixture.h
EntityOwnershipService/EntityOwnershipServiceTestFixture.cpp
EntityOwnershipService/SliceEditorEntityOwnershipTests.cpp
EntityOwnershipService/SliceEntityOwnershipTests.cpp
CameraState.cpp CameraState.cpp
InputTests.cpp InputTests.cpp
) )

@ -41,7 +41,7 @@ namespace AzNetworking
void TcpSocketManager::ProcessEvents(AZ::TimeMs maxBlockMs, const SocketEventCallback& readCallback, const SocketEventCallback& writeCallback) void TcpSocketManager::ProcessEvents(AZ::TimeMs maxBlockMs, const SocketEventCallback& readCallback, const SocketEventCallback& writeCallback)
{ {
if(static_cast<int32_t>(m_maxFd) <= 0 && m_socketFds.empty()) if(static_cast<int32_t>(m_maxFd) <= 0 || m_socketFds.empty())
{ {
// There are no available sockets to process // There are no available sockets to process
return; return;

@ -63,6 +63,9 @@ namespace AzToolsFramework
//! Signal the Python handler to stop //! Signal the Python handler to stop
virtual bool StopPython(bool silenceWarnings = false) = 0; virtual bool StopPython(bool silenceWarnings = false) = 0;
//! Query to determine if the Python VM has been initialized indicating an active state
virtual bool IsPythonActive() = 0;
//! Determines if the caller needs to wait for the Python VM to initialize (non-main thread only) //! Determines if the caller needs to wait for the Python VM to initialize (non-main thread only)
virtual void WaitForInitialization() {} virtual void WaitForInitialization() {}

@ -11,6 +11,7 @@
#include <AzFramework/Input/Buses/Notifications/InputChannelNotificationBus.h> #include <AzFramework/Input/Buses/Notifications/InputChannelNotificationBus.h>
#include <AzFramework/Input/Buses/Requests/InputChannelRequestBus.h> #include <AzFramework/Input/Buses/Requests/InputChannelRequestBus.h>
#include <AzQtComponents/Utilities/QtWindowUtilities.h>
#include <QApplication> #include <QApplication>
#include <QCursor> #include <QCursor>
@ -187,12 +188,6 @@ namespace AzToolsFramework
bool QtEventToAzInputMapper::HandlesInputEvent(const AzFramework::InputChannel& channel) const bool QtEventToAzInputMapper::HandlesInputEvent(const AzFramework::InputChannel& channel) const
{ {
const AzFramework::InputChannelId& channelId = channel.GetInputChannelId();
if (channelId == AzFramework::InputDeviceMouse::Movement::X || channelId == AzFramework::InputDeviceMouse::Movement::Y)
{
return false;
}
// We map keyboard and mouse events from Qt, so flag all events coming from those devices // We map keyboard and mouse events from Qt, so flag all events coming from those devices
// as handled by our synthetic event system. // as handled by our synthetic event system.
const AzFramework::InputDeviceId& deviceId = channel.GetInputDevice().GetInputDeviceId(); const AzFramework::InputDeviceId& deviceId = channel.GetInputDevice().GetInputDeviceId();
@ -210,6 +205,22 @@ namespace AzToolsFramework
} }
} }
void QtEventToAzInputMapper::SetCursorCaptureEnabled(bool enabled)
{
if (m_capturingCursor != enabled)
{
m_capturingCursor = enabled;
if (m_capturingCursor)
{
qApp->setOverrideCursor(Qt::BlankCursor);
}
else
{
qApp->restoreOverrideCursor();
}
}
}
bool QtEventToAzInputMapper::eventFilter(QObject* object, QEvent* event) bool QtEventToAzInputMapper::eventFilter(QObject* object, QEvent* event)
{ {
// Abort if processing isn't enabled. // Abort if processing isn't enabled.
@ -284,13 +295,25 @@ namespace AzToolsFramework
{ {
auto systemCursorChannel = auto systemCursorChannel =
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::SystemCursorPosition); GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::SystemCursorPosition);
auto movementXChannel =
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::X);
auto movementYChannel =
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::Y);
auto mouseWheelChannel = auto mouseWheelChannel =
GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::Z); GetInputChannel<AzFramework::InputChannelDeltaWithSharedPosition2D>(AzFramework::InputDeviceMouse::Movement::Z);
systemCursorChannel->ProcessRawInputEvent(m_cursorPosition->m_normalizedPositionDelta.GetLength()); systemCursorChannel->ProcessRawInputEvent(m_cursorPosition->m_normalizedPositionDelta.GetLength());
// Generate movement events based on the pixel delta divided by the DPI scaling factor, to calculate a rough approximation
// of cursor movement velocity.
movementXChannel->ProcessRawInputEvent(
m_cursorPosition->m_normalizedPositionDelta.GetX() * aznumeric_cast<float>(m_sourceWidget->width()) / m_sourceWidget->devicePixelRatioF());
movementYChannel->ProcessRawInputEvent(
m_cursorPosition->m_normalizedPositionDelta.GetY() * aznumeric_cast<float>(m_sourceWidget->height()) / m_sourceWidget->devicePixelRatioF());
mouseWheelChannel->ProcessRawInputEvent(0.f); mouseWheelChannel->ProcessRawInputEvent(0.f);
NotifyUpdateChannelIfNotIdle(systemCursorChannel, nullptr); NotifyUpdateChannelIfNotIdle(systemCursorChannel, nullptr);
NotifyUpdateChannelIfNotIdle(movementXChannel, nullptr);
NotifyUpdateChannelIfNotIdle(movementYChannel, nullptr);
NotifyUpdateChannelIfNotIdle(mouseWheelChannel, nullptr); NotifyUpdateChannelIfNotIdle(mouseWheelChannel, nullptr);
} }
@ -318,16 +341,42 @@ namespace AzToolsFramework
} }
} }
AZ::Vector2 QtEventToAzInputMapper::WidgetPositionToNormalizedPosition(QPoint position)
{
const float normalizedX = aznumeric_cast<float>(position.x()) / aznumeric_cast<float>(m_sourceWidget->width());
const float normalizedY = aznumeric_cast<float>(position.y()) / aznumeric_cast<float>(m_sourceWidget->height());
return AZ::Vector2{normalizedX, normalizedY};
}
QPoint QtEventToAzInputMapper::NormalizedPositionToWidgetPosition(AZ::Vector2 normalizedPosition)
{
const int denormalizedX = aznumeric_cast<int>(normalizedPosition.GetX() * m_sourceWidget->width());
const int denormalizedY = aznumeric_cast<int>(normalizedPosition.GetY() * m_sourceWidget->height());
return QPoint{denormalizedX, denormalizedY};
}
void QtEventToAzInputMapper::HandleMouseMoveEvent(QMouseEvent* mouseEvent) void QtEventToAzInputMapper::HandleMouseMoveEvent(QMouseEvent* mouseEvent)
{ {
AZ::Vector2 lastCursorPosition = m_cursorPosition->m_normalizedPosition;
const QPoint mousePos = mouseEvent->pos(); const QPoint mousePos = mouseEvent->pos();
const float normalizedX = aznumeric_cast<float>(mousePos.x()) / aznumeric_cast<float>(m_sourceWidget->width()); const AZ::Vector2 normalizedPosition = WidgetPositionToNormalizedPosition(mousePos);
const float normalizedY = aznumeric_cast<float>(mousePos.y()) / aznumeric_cast<float>(m_sourceWidget->height());
const AZ::Vector2 normalizedPosition(normalizedX, normalizedY);
m_cursorPosition->m_normalizedPositionDelta = normalizedPosition - m_cursorPosition->m_normalizedPosition; m_cursorPosition->m_normalizedPositionDelta = normalizedPosition - m_cursorPosition->m_normalizedPosition;
m_cursorPosition->m_normalizedPosition = normalizedPosition; m_cursorPosition->m_normalizedPosition = normalizedPosition;
ProcessPendingMouseEvents(); ProcessPendingMouseEvents();
m_mouseChannelsNeedUpdate = true; m_mouseChannelsNeedUpdate = true;
if (m_capturingCursor)
{
// Reset our cursor position to the previous point.
QPoint targetScreenPosition = m_sourceWidget->mapToGlobal(NormalizedPositionToWidgetPosition(lastCursorPosition));
AzQtComponents::SetCursorPos(targetScreenPosition);
// Even though we just set the cursor position, there are edge cases such as remote desktop that will leave
// the cursor position unchanged. For safety, we re-cache our last cursor position for delta generation.
QPoint actualWidgetPosition = m_sourceWidget->mapFromGlobal(QCursor::pos());
m_cursorPosition->m_normalizedPosition = WidgetPositionToNormalizedPosition(actualWidgetPosition);
}
} }
void QtEventToAzInputMapper::HandleKeyEvent(QKeyEvent* keyEvent) void QtEventToAzInputMapper::HandleKeyEvent(QKeyEvent* keyEvent)

@ -47,6 +47,12 @@ namespace AzToolsFramework
//! Sets whether or not this input mapper should be updating its input channels from Qt events. //! Sets whether or not this input mapper should be updating its input channels from Qt events.
void SetEnabled(bool enabled); void SetEnabled(bool enabled);
//! Sets whether or not the cursor should be constrained to the source widget and invisible.
//! Internally, this will reset the cursor position after each move event to ensure movement
//! events don't allow the cursor to escape. This can be used for typical camera controls
//! like a dolly or rotation, where mouse movement is important but cursor location is not.
void SetCursorCaptureEnabled(bool enabled);
// QObject overrides... // QObject overrides...
bool eventFilter(QObject* object, QEvent* event) override; bool eventFilter(QObject* object, QEvent* event) override;
@ -106,6 +112,11 @@ namespace AzToolsFramework
// Processes any pending mouse movement events, this allows mouse movement channels to close themselves. // Processes any pending mouse movement events, this allows mouse movement channels to close themselves.
void ProcessPendingMouseEvents(); void ProcessPendingMouseEvents();
// Converts a point in logical source widget space [0..m_sourceWidget->size()] to normalized [0..1] space.
AZ::Vector2 WidgetPositionToNormalizedPosition(QPoint position);
// Converts a point in normalized [0..1] space to logical source widget space [0..m_sourceWidget->size()].
QPoint NormalizedPositionToWidgetPosition(AZ::Vector2 normalizedPosition);
// Handle mouse click events. // Handle mouse click events.
void HandleMouseButtonEvent(QMouseEvent* mouseEvent); void HandleMouseButtonEvent(QMouseEvent* mouseEvent);
// Handle mouse move events. // Handle mouse move events.
@ -144,6 +155,8 @@ namespace AzToolsFramework
bool m_mouseChannelsNeedUpdate = false; bool m_mouseChannelsNeedUpdate = false;
// Flags whether or not Qt events should currently be processed. // Flags whether or not Qt events should currently be processed.
bool m_enabled = true; bool m_enabled = true;
// Flags whether or not the cursor is being constrained to the source widget (for invisible mouse movement).
bool m_capturingCursor = false;
// Our viewport-specific AZ devices. We control their internal input channel states. // Our viewport-specific AZ devices. We control their internal input channel states.
AZStd::unique_ptr<EditorQtMouseDevice> m_mouseDevice; AZStd::unique_ptr<EditorQtMouseDevice> m_mouseDevice;

@ -172,20 +172,23 @@ namespace AzToolsFramework
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId); PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
//apply patch to template //apply patch to template
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference, AZ::JsonSerializationResult::ResultCode result =
templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch); PrefabDomUtils::ApplyPatches(templateDomReference, templateDomReference.GetAllocator(), providedPatch);
//trigger propagation //trigger propagation
if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success) if (result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Success)
{ {
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true); AZ_Error("Prefab", false, "Patch was not successfully applied.");
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude); return false;
return true;
} }
else else
{ {
AZ_Error("Prefab", false, "Patch was not successfully applied"); AZ_Error(
return false; "Prefab", result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip,
"Some of the patches are not successfully applied.");
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude);
return true;
} }
} }

@ -176,12 +176,17 @@ namespace AzToolsFramework
} }
else else
{ {
AZ::JsonSerializationResult::ResultCode applyPatchResult = AZ::JsonSerialization::ApplyPatch( AZ::JsonSerializationResult::ResultCode applyPatchResult =
sourceTemplateDomCopy, PrefabDomUtils::ApplyPatches(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator(), patchesReference->get());
targetTemplatePrefabDom.GetAllocator(),
patchesReference->get(),
AZ::JsonMergeApproach::JsonPatch);
linkedInstanceDom.CopyFrom(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator()); linkedInstanceDom.CopyFrom(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator());
PrefabDomValueReference sourceTemplateName =
PrefabDomUtils::FindPrefabDomValue(sourceTemplateDomCopy, PrefabDomUtils::SourceName);
AZ_Assert(sourceTemplateName && sourceTemplateName->get().IsString(), "A valid source template name couldn't be found");
PrefabDomValueReference targetTemplateName =
PrefabDomUtils::FindPrefabDomValue(targetTemplatePrefabDom, PrefabDomUtils::SourceName);
AZ_Assert(targetTemplateName && targetTemplateName->get().IsString(), "A valid target template name couldn't be found");
if (applyPatchResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed) if (applyPatchResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
{ {
AZ_Error( AZ_Error(
@ -190,6 +195,14 @@ namespace AzToolsFramework
m_sourceTemplateId, m_targetTemplateId); m_sourceTemplateId, m_targetTemplateId);
return false; return false;
} }
if (applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip)
{
AZ_Error(
"Prefab", false,
"Link::UpdateTarget - Some of the patches couldn't be applied on the source template '%s' present under the "
"target Template '%s'.",
sourceTemplateName->get().GetString(), targetTemplateName->get().GetString());
}
} }
// This is a guardrail to ensure the linked instance dom always has the LinkId value // This is a guardrail to ensure the linked instance dom always has the LinkId value

@ -236,6 +236,26 @@ namespace AzToolsFramework
return findInstancesResult->get(); return findInstancesResult->get();
} }
AZ::JsonSerializationResult::ResultCode ApplyPatches(
PrefabDomValue& prefabDomToApplyPatchesOn, PrefabDom::AllocatorType& allocator, const PrefabDomValue& patches)
{
auto issueReportingCallback = [](AZStd::string_view, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view) -> AZ::JsonSerializationResult::ResultCode
{
using namespace AZ::JsonSerializationResult;
if (result.GetProcessing() == Processing::Halted)
{
return ResultCode(result.GetTask(), Outcomes::PartialSkip);
}
return result;
};
AZ::JsonApplyPatchSettings applyPatchSettings;
applyPatchSettings.m_reporting = AZStd::move(issueReportingCallback);
return AZ::JsonSerialization::ApplyPatch(
prefabDomToApplyPatchesOn, allocator, patches, AZ::JsonMergeApproach::JsonPatch, applyPatchSettings);
}
void PrintPrefabDomValue( void PrintPrefabDomValue(
[[maybe_unused]] const AZStd::string_view printMessage, [[maybe_unused]] const AZStd::string_view printMessage,
[[maybe_unused]] const PrefabDomValue& prefabDomValue) [[maybe_unused]] const PrefabDomValue& prefabDomValue)

@ -7,6 +7,7 @@
#pragma once #pragma once
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
#include <AzCore/std/optional.h> #include <AzCore/std/optional.h>
#include <AzCore/Asset/AssetCommon.h> #include <AzCore/Asset/AssetCommon.h>
#include <AzToolsFramework/Prefab/Instance/Instance.h> #include <AzToolsFramework/Prefab/Instance/Instance.h>
@ -122,6 +123,11 @@ namespace AzToolsFramework
*/ */
PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom); PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom);
AZ::JsonSerializationResult::ResultCode ApplyPatches(
PrefabDomValue& prefabDomToApplyPatchesOn,
PrefabDom::AllocatorType& allocator,
const PrefabDomValue& patches);
/** /**
* Prints the contents of the given prefab DOM value to the debug output console in a readable format. * Prints the contents of the given prefab DOM value to the debug output console in a readable format.
* @param printMessage The message that will be printed before printing the PrefabDomValue * @param printMessage The message that will be printed before printing the PrefabDomValue

@ -261,8 +261,13 @@ namespace AzToolsFramework
instanceDom.CopyFrom(instanceDomRef->get(), instanceDom.GetAllocator()); instanceDom.CopyFrom(instanceDomRef->get(), instanceDom.GetAllocator());
//apply the patch to the template within the target //apply the patch to the template within the target
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(instanceDom, AZ::JsonSerializationResult::ResultCode result = PrefabDomUtils::ApplyPatches(instanceDom, instanceDom.GetAllocator(), patch);
instanceDom.GetAllocator(), patch, AZ::JsonMergeApproach::JsonPatch);
AZ_Error(
"Prefab",
result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip ||
result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
"Some of the patches are not successfully applied.");
//remove the link id placed into the instance //remove the link id placed into the instance
auto linkIdIter = instanceDom.FindMember(PrefabDomUtils::LinkIdName); auto linkIdIter = instanceDom.FindMember(PrefabDomUtils::LinkIdName);

@ -22,11 +22,11 @@ namespace AzToolsFramework
/// @name Reverse URLs. /// @name Reverse URLs.
/// Used to identify common actions and override them when necessary. /// Used to identify common actions and override them when necessary.
//@{ //@{
static const AZ::Crc32 s_backAction = AZ_CRC("com.amazon.action.common.back", 0xd772a2af); static const AZ::Crc32 s_backAction = AZ_CRC("com.o3de.action.common.back", 0xd772a2af);
static const AZ::Crc32 s_deleteAction = AZ_CRC("com.amazon.action.common.delete", 0x5731f6cb); static const AZ::Crc32 s_deleteAction = AZ_CRC("com.o3de.action.common.delete", 0x5731f6cb);
static const AZ::Crc32 s_duplicateAction = AZ_CRC("com.amazon.action.common.duplicate", 0x08ccf461); static const AZ::Crc32 s_duplicateAction = AZ_CRC("com.o3de.action.common.duplicate", 0x08ccf461);
static const AZ::Crc32 s_nextComponentMode = AZ_CRC("com.amazon.action.common.nextComponentMode", 0xcc26094f); static const AZ::Crc32 s_nextComponentMode = AZ_CRC("com.o3de.action.common.nextComponentMode", 0xcc26094f);
static const AZ::Crc32 s_previousComponentMode = AZ_CRC("com.amazon.action.common.previousComponentMode", 0x0d18ff39); static const AZ::Crc32 s_previousComponentMode = AZ_CRC("com.o3de.action.common.previousComponentMode", 0x0d18ff39);
//@} //@}
/// Specific Action properties to be sent to a type implementing /// Specific Action properties to be sent to a type implementing

@ -276,11 +276,6 @@ namespace AzToolsFramework
virtual void EndCursorCapture() = 0; virtual void EndCursorCapture() = 0;
//! Gets the most recent recorded cursor position in the viewport in screen space coordinates. //! Gets the most recent recorded cursor position in the viewport in screen space coordinates.
virtual AzFramework::ScreenPoint ViewportCursorScreenPosition() = 0; virtual AzFramework::ScreenPoint ViewportCursorScreenPosition() = 0;
//! Gets the cursor position recorded prior to the most recent cursor position.
//! Note: The cursor may be captured by the viewport, in which case this may not correspond to the last result
//! from ViewportCursorScreenPosition. This method will always return the correct position to generate a mouse
//! position delta.
virtual AZStd::optional<AzFramework::ScreenPoint> PreviousViewportCursorScreenPosition() = 0;
//! Is mouse over viewport. //! Is mouse over viewport.
virtual bool IsMouseOver() const = 0; virtual bool IsMouseOver() const = 0;

@ -98,7 +98,7 @@ namespace AzToolsFramework
{ {
} }
AZ::Crc32 m_uri; //!< Unique identifier for the Action. (In the form 'com.amazon.action.---"). AZ::Crc32 m_uri; //!< Unique identifier for the Action. (In the form 'com.o3de.action.---").
AZStd::vector<AZStd::function<void()>> m_callbacks; //!< Callbacks associated with this Action (note: with multi-selections AZStd::vector<AZStd::function<void()>> m_callbacks; //!< Callbacks associated with this Action (note: with multi-selections
//!< there will be a callback per Entity/Component). //!< there will be a callback per Entity/Component).
AZStd::unique_ptr<QAction> m_action; //!< The QAction associated with the overrideWidget for all ComponentMode actions. AZStd::unique_ptr<QAction> m_action; //!< The QAction associated with the overrideWidget for all ComponentMode actions.

@ -76,6 +76,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
PRIVATE PRIVATE
AZ::AzTestShared AZ::AzTestShared
3rdParty::Qt::Test 3rdParty::Qt::Test
AZ::AzFrameworkTestShared
AZ::AzToolsFramework AZ::AzToolsFramework
AZ::AzToolsFrameworkTestCommon AZ::AzToolsFrameworkTestCommon
AZ::AzManipulatorTestFramework.Static AZ::AzManipulatorTestFramework.Static

@ -11,6 +11,7 @@
#include <AzCore/Memory/Memory.h> #include <AzCore/Memory/Memory.h>
#include <AzCore/std/smart_ptr/unique_ptr.h> #include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/UserSettings/UserSettingsComponent.h> #include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzCore/IO/FileIO.h>
#include <Tests/AZTestShared/Utils/Utils.h> #include <Tests/AZTestShared/Utils/Utils.h>
#include <AzToolsFramework/Archive/ArchiveAPI.h> #include <AzToolsFramework/Archive/ArchiveAPI.h>
#include <AzFramework/StringFunc/StringFunc.h> #include <AzFramework/StringFunc/StringFunc.h>
@ -23,6 +24,7 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QTemporaryDir> #include <QTemporaryDir>
#include <QTextStream> #include <QTextStream>
#include <Utils/Utils.h>
namespace UnitTest namespace UnitTest
{ {
@ -72,7 +74,7 @@ namespace UnitTest
void CreateArchiveFolder( QString archiveFolderName, QStringList fileList ) void CreateArchiveFolder( QString archiveFolderName, QStringList fileList )
{ {
QDir tempPath = QDir(m_tempDir.path()).filePath(archiveFolderName); QDir tempPath = QDir(m_tempDir.GetDirectory()).filePath(archiveFolderName);
for (const auto& thisFile : fileList) for (const auto& thisFile : fileList)
{ {
@ -88,12 +90,12 @@ namespace UnitTest
QString GetArchivePath() QString GetArchivePath()
{ {
return QDir(m_tempDir.path()).filePath("TestArchive.pak"); return QDir(m_tempDir.GetDirectory()).filePath("TestArchive.pak");
} }
QString GetArchiveFolder() QString GetArchiveFolder()
{ {
return QDir(m_tempDir.path()).filePath(GetArchiveFolderName()); return QDir(m_tempDir.GetDirectory()).filePath(GetArchiveFolderName());
} }
bool CreateArchive() bool CreateArchive()
@ -111,6 +113,11 @@ namespace UnitTest
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests. // in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr)
{
fileIoBase->SetAlias("@assets@", m_tempDir.GetDirectory());
}
} }
void TearDown() override void TearDown() override
@ -120,7 +127,7 @@ namespace UnitTest
} }
AZStd::unique_ptr<ToolsTestApplication> m_app; AZStd::unique_ptr<ToolsTestApplication> m_app;
QTemporaryDir m_tempDir {QDir(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).filePath("ArchiveTests-")}; UnitTest::ScopedTemporaryDirectory m_tempDir;
}; };
#if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS #if AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
@ -129,7 +136,7 @@ namespace UnitTest
TEST_F(ArchiveTest, CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated) TEST_F(ArchiveTest, CreateArchiveBlocking_FilesAtThreeDepths_ArchiveCreated)
#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
{ {
EXPECT_TRUE(m_tempDir.isValid()); EXPECT_TRUE(m_tempDir.IsValid());
CreateArchiveFolder(); CreateArchiveFolder();
bool createResult = CreateArchive(); bool createResult = CreateArchive();
@ -143,7 +150,7 @@ namespace UnitTest
TEST_F(ArchiveTest, ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound) TEST_F(ArchiveTest, ListFilesInArchiveBlocking_FilesAtThreeDepths_FilesFound)
#endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS #endif // AZ_TRAIT_DISABLE_FAILED_ARCHIVE_TESTS
{ {
EXPECT_TRUE(m_tempDir.isValid()); EXPECT_TRUE(m_tempDir.IsValid());
CreateArchiveFolder(); CreateArchiveFolder();
EXPECT_EQ(CreateArchive(), true); EXPECT_EQ(CreateArchive(), true);
@ -203,7 +210,9 @@ namespace UnitTest
} }
bool catalogCreated{ false }; bool catalogCreated{ false };
AZ_TEST_START_TRACE_SUPPRESSION;
AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toStdString().c_str(), true); AzToolsFramework::AssetBundleCommandsBus::BroadcastResult(catalogCreated, &AzToolsFramework::AssetBundleCommandsBus::Events::CreateDeltaCatalog, GetArchivePath().toStdString().c_str(), true);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // produces different counts in different platforms
EXPECT_EQ(catalogCreated, true); EXPECT_EQ(catalogCreated, true);
} }
} }

@ -21,6 +21,7 @@
#include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h> #include <AzToolsFramework/AssetCatalog/PlatformAddressedAssetCatalog.h>
#include <AzToolsFramework/UnitTest/ToolsTestApplication.h> #include <AzToolsFramework/UnitTest/ToolsTestApplication.h>
#include <AzCore/UserSettings/UserSettingsComponent.h> #include <AzCore/UserSettings/UserSettingsComponent.h>
#include <Utils/Utils.h>
namespace // anonymous namespace // anonymous
{ {
@ -54,9 +55,11 @@ namespace UnitTest
m_localFileIO = aznew AZ::IO::LocalFileIO(); m_localFileIO = aznew AZ::IO::LocalFileIO();
m_priorFileIO = AZ::IO::FileIOBase::GetInstance(); m_priorFileIO = AZ::IO::FileIOBase::GetInstance();
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_localFileIO); AZ::IO::FileIOBase::SetInstance(m_localFileIO);
AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", GetTestFolderPath().c_str()); AZ::IO::FileIOBase::GetInstance()->SetAlias("@assets@", m_tempDir.GetDirectory());
AZStd::string assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(AzFramework::PlatformId::PC); AZStd::string assetRoot = AzToolsFramework::PlatformAddressedAssetCatalog::GetAssetRootForPlatform(AzFramework::PlatformId::PC);
for (int idx = 0; idx < TotalAssets; idx++) for (int idx = 0; idx < TotalAssets; idx++)
@ -68,9 +71,11 @@ namespace UnitTest
assetRegistry.RegisterAsset(m_assets[idx], info); assetRegistry.RegisterAsset(m_assets[idx], info);
AzFramework::StringFunc::Path::Join(assetRoot.c_str(), info.m_relativePath.c_str(), m_assetsPath[idx]); AzFramework::StringFunc::Path::Join(assetRoot.c_str(), info.m_relativePath.c_str(), m_assetsPath[idx]);
AZ_TEST_START_TRACE_SUPPRESSION;
if (m_fileStreams[idx].Open(m_assetsPath[idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) if (m_fileStreams[idx].Open(m_assetsPath[idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{ {
m_fileStreams[idx].Write(info.m_relativePath.size(), info.m_relativePath.data()); m_fileStreams[idx].Write(info.m_relativePath.size(), info.m_relativePath.data());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder
} }
else else
{ {
@ -114,10 +119,12 @@ namespace UnitTest
// Modify contents of asset2 // Modify contents of asset2
int fileIndex = 2; int fileIndex = 2;
AZ_TEST_START_TRACE_SUPPRESSION;
if (m_fileStreams[fileIndex].Open(m_assetsPath[fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) if (m_fileStreams[fileIndex].Open(m_assetsPath[fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{ {
AZStd::string fileContent = AZStd::string::format("new Asset%d.txt", fileIndex);// changing file content AZStd::string fileContent = AZStd::string::format("new Asset%d.txt", fileIndex);// changing file content
m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder
} }
else else
{ {
@ -126,10 +133,12 @@ namespace UnitTest
// Modify contents of asset 4 // Modify contents of asset 4
fileIndex = 4; fileIndex = 4;
AZ_TEST_START_TRACE_SUPPRESSION;
if (m_fileStreams[fileIndex].Open(m_assetsPath[fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) if (m_fileStreams[fileIndex].Open(m_assetsPath[fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{ {
AZStd::string fileContent = AZStd::string::format("new Asset%d.txt", fileIndex);// changing file content AZStd::string fileContent = AZStd::string::format("new Asset%d.txt", fileIndex);// changing file content
m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[fileIndex].Write(fileContent.size(), fileContent.c_str());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // writing to asset cache folder
} }
else else
{ {
@ -151,7 +160,9 @@ namespace UnitTest
{ {
if (fileIO->Exists(TempFiles[idx])) if (fileIO->Exists(TempFiles[idx]))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(TempFiles[idx]); fileIO->Remove(TempFiles[idx]);
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // deleting from asset cache folder
} }
} }
@ -162,19 +173,24 @@ namespace UnitTest
m_fileStreams[idx].Close(); m_fileStreams[idx].Close();
if (fileIO->Exists(m_assetsPath[idx].c_str())) if (fileIO->Exists(m_assetsPath[idx].c_str()))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(m_assetsPath[idx].c_str()); fileIO->Remove(m_assetsPath[idx].c_str());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // deleting from asset cache folder
} }
} }
auto pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC); auto pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC);
if (fileIO->Exists(pcCatalogFile.c_str())) if (fileIO->Exists(pcCatalogFile.c_str()))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(pcCatalogFile.c_str()); fileIO->Remove(pcCatalogFile.c_str());
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // deleting from asset cache folder
} }
delete m_pcCatalog; delete m_pcCatalog;
delete m_localFileIO; delete m_localFileIO;
m_localFileIO = nullptr; m_localFileIO = nullptr;
AZ::IO::FileIOBase::SetInstance(nullptr);
AZ::IO::FileIOBase::SetInstance(m_priorFileIO); AZ::IO::FileIOBase::SetInstance(m_priorFileIO);
m_application->Stop(); m_application->Stop();
delete m_application; delete m_application;
@ -726,6 +742,7 @@ namespace UnitTest
} }
ToolsTestApplication* m_application; ToolsTestApplication* m_application;
UnitTest::ScopedTemporaryDirectory m_tempDir;
AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog; AzToolsFramework::PlatformAddressedAssetCatalog* m_pcCatalog;
AZ::IO::FileIOBase* m_priorFileIO = nullptr; AZ::IO::FileIOBase* m_priorFileIO = nullptr;
AZ::IO::FileIOBase* m_localFileIO = nullptr; AZ::IO::FileIOBase* m_localFileIO = nullptr;

@ -87,10 +87,12 @@ namespace UnitTest
for (int idx = 0; idx < s_totalAssets; idx++) for (int idx = 0; idx < s_totalAssets; idx++)
{ {
AzFramework::StringFunc::Path::Join(assetRoot.c_str(), m_assetsPath[idx].c_str(), m_assetsPathFull[platformCount][idx]); AzFramework::StringFunc::Path::Join(assetRoot.c_str(), m_assetsPath[idx].c_str(), m_assetsPathFull[platformCount][idx]);
AZ_TEST_START_TRACE_SUPPRESSION;
if (m_fileStreams[platformCount][idx].Open(m_assetsPathFull[platformCount][idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) if (m_fileStreams[platformCount][idx].Open(m_assetsPathFull[platformCount][idx].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{ {
m_fileStreams[platformCount][idx].Write(m_assetsPath[idx].size(), m_assetsPath[idx].data()); m_fileStreams[platformCount][idx].Write(m_assetsPath[idx].size(), m_assetsPath[idx].data());
m_fileStreams[platformCount][idx].Close(); m_fileStreams[platformCount][idx].Close();
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, only invalid for PC, not invalid in Jenkins
} }
else else
{ {
@ -112,7 +114,9 @@ namespace UnitTest
m_testDynamicSliceAssetId = testDynamicSliceAsset; m_testDynamicSliceAssetId = testDynamicSliceAsset;
m_assetRegistry->RegisterAsset(testDynamicSliceAsset, dynamicSliceAssetInfo); m_assetRegistry->RegisterAsset(testDynamicSliceAsset, dynamicSliceAssetInfo);
AZ_TEST_START_TRACE_SUPPRESSION;
AZ::IO::FileIOStream dynamicSliceFileIOStream(TestDynamicSliceAssetPath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); AZ::IO::FileIOStream dynamicSliceFileIOStream(TestDynamicSliceAssetPath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
AZ::Data::AssetInfo sliceAssetInfo; AZ::Data::AssetInfo sliceAssetInfo;
sliceAssetInfo.m_relativePath = TestSliceAssetPath; sliceAssetInfo.m_relativePath = TestSliceAssetPath;
@ -124,7 +128,9 @@ namespace UnitTest
secondSliceAssetInfo.m_assetId = secondTestSliceAsset; secondSliceAssetInfo.m_assetId = secondTestSliceAsset;
m_assetRegistry->RegisterAsset(secondTestSliceAsset, secondSliceAssetInfo); m_assetRegistry->RegisterAsset(secondTestSliceAsset, secondSliceAssetInfo);
AZ_TEST_START_TRACE_SUPPRESSION;
AZ::IO::FileIOStream sliceFileIOStream(TestSliceAssetPath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText); AZ::IO::FileIOStream sliceFileIOStream(TestSliceAssetPath, AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
// asset0 -> asset1 -> asset2 -> asset4 // asset0 -> asset1 -> asset2 -> asset4
// --> asset3 // --> asset3
@ -186,7 +192,6 @@ namespace UnitTest
AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath());
assetRoot /= "Cache"; assetRoot /= "Cache";
AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str()); AZ::IO::FileIOBase::GetInstance()->SetAlias("@root@", assetRoot.c_str());
} }
void TearDown() override void TearDown() override
@ -195,7 +200,9 @@ namespace UnitTest
if (fileIO->Exists(s_catalogFile)) if (fileIO->Exists(s_catalogFile))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(s_catalogFile); fileIO->Remove(s_catalogFile);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins
} }
for (size_t platformCount = 0; platformCount < s_totalTestPlatforms; ++platformCount) for (size_t platformCount = 0; platformCount < s_totalTestPlatforms; ++platformCount)
@ -206,26 +213,34 @@ namespace UnitTest
// we need to close the handle before we try to remove the file // we need to close the handle before we try to remove the file
if (fileIO->Exists(m_assetsPathFull[platformCount][idx].c_str())) if (fileIO->Exists(m_assetsPathFull[platformCount][idx].c_str()))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(m_assetsPathFull[platformCount][idx].c_str()); fileIO->Remove(m_assetsPathFull[platformCount][idx].c_str());
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins
} }
} }
} }
if (fileIO->Exists(TestSliceAssetPath)) if (fileIO->Exists(TestSliceAssetPath))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(TestSliceAssetPath); fileIO->Remove(TestSliceAssetPath);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins
} }
if (fileIO->Exists(TestDynamicSliceAssetPath)) if (fileIO->Exists(TestDynamicSliceAssetPath))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(TestDynamicSliceAssetPath); fileIO->Remove(TestDynamicSliceAssetPath);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins
} }
auto pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC); auto pcCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::PC);
auto androidCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID); auto androidCatalogFile = AzToolsFramework::PlatformAddressedAssetCatalog::GetCatalogRegistryPathForPlatform(AzFramework::PlatformId::ANDROID_ID);
if (fileIO->Exists(pcCatalogFile.c_str())) if (fileIO->Exists(pcCatalogFile.c_str()))
{ {
AZ_TEST_START_TRACE_SUPPRESSION;
fileIO->Remove(pcCatalogFile.c_str()); fileIO->Remove(pcCatalogFile.c_str());
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // deleting from asset cache folder, not invalid in Jenkins
} }
if (fileIO->Exists(androidCatalogFile.c_str())) if (fileIO->Exists(androidCatalogFile.c_str()))
@ -266,7 +281,9 @@ namespace UnitTest
AZ::IO::SystemFile::SetWritable(filePath.c_str(), false); AZ::IO::SystemFile::SetWritable(filePath.c_str(), false);
// Attempt to save to the same file. Should not be allowed. // Attempt to save to the same file. Should not be allowed.
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_FALSE(m_assetSeedManager->Save(filePath)); EXPECT_FALSE(m_assetSeedManager->Save(filePath));
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
// Clean up the test environment // Clean up the test environment
AZ::IO::SystemFile::SetWritable(filePath.c_str(), true); AZ::IO::SystemFile::SetWritable(filePath.c_str(), true);
@ -290,7 +307,9 @@ namespace UnitTest
AZ::IO::SystemFile::SetWritable(filePath.c_str(), false); AZ::IO::SystemFile::SetWritable(filePath.c_str(), false);
// Attempt to save to the same file. Should not be allowed. // Attempt to save to the same file. Should not be allowed.
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_FALSE(m_assetSeedManager->SaveAssetFileInfo(filePath, AzFramework::PlatformFlags::Platform_PC, {})); EXPECT_FALSE(m_assetSeedManager->SaveAssetFileInfo(filePath, AzFramework::PlatformFlags::Platform_PC, {}));
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
// Clean up the test environment // Clean up the test environment
AZ::IO::SystemFile::SetWritable(filePath.c_str(), true); AZ::IO::SystemFile::SetWritable(filePath.c_str(), true);
@ -357,7 +376,9 @@ namespace UnitTest
m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_PC); m_assetSeedManager->AddSeedAsset(assets[2], AzFramework::PlatformFlags::Platform_PC);
// Step we are testing // Step we are testing
AZ_TEST_START_TRACE_SUPPRESSION;
m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ANDROID_ID); m_assetSeedManager->AddPlatformToAllSeeds(AzFramework::PlatformId::ANDROID_ID);
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
// Verification // Verification
AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID; AzFramework::PlatformFlags expectedPlatformFlags = AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_ANDROID;
@ -623,11 +644,13 @@ namespace UnitTest
EXPECT_EQ(assetList1.m_fileInfoList.size(), 1); EXPECT_EQ(assetList1.m_fileInfoList.size(), 1);
EXPECT_TRUE(Search(assetList1, assets[fileIndex])); EXPECT_TRUE(Search(assetList1, assets[fileIndex]));
AZ_TEST_START_TRACE_SUPPRESSION;
if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{ {
AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex); AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex);
m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str());
m_fileStreams[0][fileIndex].Close(); m_fileStreams[0][fileIndex].Close();
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
} }
AzToolsFramework::AssetFileInfoList assetList2 = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC); AzToolsFramework::AssetFileInfoList assetList2 = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);
@ -654,11 +677,13 @@ namespace UnitTest
EXPECT_EQ(assetList1.m_fileInfoList.size(), 1); EXPECT_EQ(assetList1.m_fileInfoList.size(), 1);
EXPECT_TRUE(Search(assetList1, assets[fileIndex])); EXPECT_TRUE(Search(assetList1, assets[fileIndex]));
AZ_TEST_START_TRACE_SUPPRESSION;
if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath))
{ {
AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex + 1);// changing file content AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex + 1);// changing file content
m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str());
m_fileStreams[0][fileIndex].Close(); m_fileStreams[0][fileIndex].Close();
AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT; // writing to asset cache folder, not invalid in Jenkins
} }
AzToolsFramework::AssetFileInfoList assetList2 = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC); AzToolsFramework::AssetFileInfoList assetList2 = m_assetSeedManager->GetDependencyList(AzFramework::PlatformId::PC);

@ -196,7 +196,7 @@ namespace AzToolsFramework
AZStd::vector<AzToolsFramework::ActionOverride> PlaceHolderComponentMode::PopulateActionsImpl() AZStd::vector<AzToolsFramework::ActionOverride> PlaceHolderComponentMode::PopulateActionsImpl()
{ {
const AZ::Crc32 placeHolderComponentModeAction = AZ_CRC_CE("com.amazon.action.placeholder.test"); const AZ::Crc32 placeHolderComponentModeAction = AZ_CRC_CE("com.o3de.action.placeholder.test");
return AZStd::vector<AzToolsFramework::ActionOverride> return AZStd::vector<AzToolsFramework::ActionOverride>
{ {

@ -493,7 +493,10 @@ namespace UnitTest
// Add placeholder component which implements component mode. // Add placeholder component which implements component mode.
entity->CreateComponent<PlaceHolderComponent>(); entity->CreateComponent<PlaceHolderComponent>();
AZ_TEST_START_TRACE_SUPPRESSION;
entity->Activate(); entity->Activate();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save