Merge remote-tracking branch 'upstream/development' into hultonha_LYN-2349_tube_delete_crash
Signed-off-by: hultonha <hultonha@amazon.co.uk>
This commit is contained in:
+5
-5
@@ -6,13 +6,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
import psutil
|
||||
|
||||
import ly_test_tools.log.log_monitor
|
||||
import ly_test_tools.environment.process_utils as process_utils
|
||||
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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ def launch_and_validate_results_launcher(launcher, level, remote_console_instanc
|
||||
return port_listening
|
||||
|
||||
if null_renderer:
|
||||
launcher.args.extend(["-NullRenderer"])
|
||||
launcher.args.extend(["-rhi=Null"])
|
||||
|
||||
# Start the Launcher
|
||||
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
|
||||
send_command_and_expect_response(remote_console_instance,
|
||||
f"map {level}",
|
||||
"LEVEL_LOAD_COMPLETE", timeout=30)
|
||||
f"LoadLevel {level}",
|
||||
"LEVEL_LOAD_END", timeout=30)
|
||||
|
||||
# Monitor the console for expected lines
|
||||
for line in expected_lines:
|
||||
|
||||
+3
-21
@@ -36,8 +36,8 @@ class TestAltitudeFilterFilterStageToggle(EditorTestHelper):
|
||||
:return: None
|
||||
"""
|
||||
|
||||
PREPROCESS_INSTANCE_COUNT = 24
|
||||
POSTPROCESS_INSTANCE_COUNT = 18
|
||||
PREPROCESS_INSTANCE_COUNT = 44
|
||||
POSTPROCESS_INSTANCE_COUNT = 34
|
||||
|
||||
# Create empty 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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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))
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 10.0)
|
||||
|
||||
# Set a Min Altitude of 38 and Max of 40 in Vegetation Altitude Filter
|
||||
vegetation.get_set_test(3, "Configuration|Altitude Min", 38.0)
|
||||
|
||||
+7
-12
@@ -9,9 +9,10 @@ import sys
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.components as components
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
@@ -83,18 +84,12 @@ class TestDynamicSliceInstanceSpawnerEmbeddedEditor(EditorTestHelper):
|
||||
self.log(f"Expected {num_expected_instances} instances - Found {num_found} 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)
|
||||
camera_component = ["Camera"]
|
||||
new_entity_id2 = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", cam_position, EntityId.EntityId()
|
||||
)
|
||||
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))
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
|
||||
+9
-14
@@ -11,7 +11,8 @@ sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.asset as asset
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.components as components
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
@@ -68,7 +69,7 @@ class TestDynamicSliceInstanceSpawnerExternalEditor(EditorTestHelper):
|
||||
veg_area_required_components = ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List",
|
||||
"Script Canvas"]
|
||||
new_entity_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
|
||||
)
|
||||
if new_entity_id.IsValid():
|
||||
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.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
|
||||
entity_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
camera_component = ["Camera"]
|
||||
new_entity_id2 = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
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))
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(512.0, 500.0, 35.0)
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
|
||||
# 6) Save and export to engine
|
||||
general.save_level()
|
||||
|
||||
+10
-16
@@ -18,9 +18,9 @@ import azlmbr.areasystem as areasystem
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.components as components
|
||||
import azlmbr.math as math
|
||||
import azlmbr.entity as EntityId
|
||||
import azlmbr.entity as entity
|
||||
import azlmbr.paths
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
|
||||
@@ -134,20 +134,14 @@ class TestVegLayerBlenderCreated(EditorTestHelper):
|
||||
purple_count += 1
|
||||
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
|
||||
entity_position = math.Vector3(500.0, 500.0, 47.0)
|
||||
rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
|
||||
camera_component = ["Camera"]
|
||||
camera_id = editor.ToolsApplicationRequestBus(
|
||||
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, EntityId.EntityId()
|
||||
)
|
||||
if camera_id.IsValid():
|
||||
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)
|
||||
# 5) Move the default Camera entity for testing in the launcher
|
||||
cam_position = math.Vector3(500.0, 500.0, 47.0)
|
||||
cam_rot_degrees_vector = math.Vector3(radians(-55.0), radians(28.5), radians(-17.0))
|
||||
search_filter = entity.SearchFilter()
|
||||
search_filter.names = ["Camera"]
|
||||
search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)
|
||||
components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position)
|
||||
azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector)
|
||||
|
||||
# 6) Save and export level
|
||||
general.save_level()
|
||||
|
||||
+5
-22
@@ -34,8 +34,8 @@ class TestLayerSpawnerFilterStageToggle(EditorTestHelper):
|
||||
:return: None
|
||||
"""
|
||||
|
||||
PREPROCESS_INSTANCE_COUNT = 425
|
||||
POSTPROCESS_INSTANCE_COUNT = 430
|
||||
PREPROCESS_INSTANCE_COUNT = 21
|
||||
POSTPROCESS_INSTANCE_COUNT = 19
|
||||
|
||||
# Create empty 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 Position Modifier")
|
||||
|
||||
|
||||
# Create a child entity under vegetation area
|
||||
child_entity = hydra.Entity("child_entity")
|
||||
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 Y|Gradient|Gradient Entity Id", child_entity.id)
|
||||
|
||||
|
||||
# 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 Max", 35.0)
|
||||
vegetation_entity.get_set_test(3, "Configuration|Altitude Min", 34.0)
|
||||
vegetation_entity.get_set_test(3, "Configuration|Altitude Max", 38.0)
|
||||
|
||||
# Add entity with Mesh to replicate creation of hills and a flat surface to plant on
|
||||
dynveg.create_surface_entity("Flat Surface", position, 32.0, 32.0, 1.0)
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0, 4.0, 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")
|
||||
hill_entity = dynveg.create_mesh_surface_entity_with_slopes("hill", position, 4.0)
|
||||
|
||||
# Set the filter stage to preprocess and postprocess respectively and verify instance count
|
||||
vegetation_entity.get_set_test(0, "Configuration|Filter Stage", 1)
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import azlmbr.legacy.general as general
|
||||
import azlmbr.math as math
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
+1
-16
@@ -82,22 +82,7 @@ class test_MeshBlocker_InstancesBlockedByMesh(EditorTestHelper):
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", cubeId)
|
||||
components.TransformBus(bus.Event, "SetLocalScale", blocker_entity.id, math.Vector3(2.0, 2.0, 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")
|
||||
components.TransformBus(bus.Event, "SetLocalUniformScale", blocker_entity.id, 2.0)
|
||||
|
||||
# Verify spawned instance counts are accurate after addition of Blocker Entity
|
||||
num_expected = 160 # Number of "PurpleFlower"s that plant on a 10 x 10 surface minus 2m blocker cube
|
||||
|
||||
+1
-16
@@ -88,24 +88,9 @@ class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorTestHelper):
|
||||
bus.Broadcast, "GetAssetIdByPath", os.path.join("objects", "_primitives", "_box_1x1.azmodel"), math.Uuid(),
|
||||
False)
|
||||
blocker_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_id)
|
||||
components.TransformBus(bus.Event, "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))
|
||||
|
||||
# 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
|
||||
blocker_entity.get_set_test(0, "Configuration|Mesh Height Percent Max", 0.8)
|
||||
|
||||
|
||||
-2
@@ -90,7 +90,6 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows'])
|
||||
@pytest.mark.skip # ATOM-14703
|
||||
def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level,
|
||||
remote_console_instance, project, launcher_platform):
|
||||
|
||||
@@ -126,7 +125,6 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows'])
|
||||
@pytest.mark.skip # ATOM-14703
|
||||
def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level,
|
||||
remote_console_instance, project, launcher_platform):
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ class TestLayerBlender(object):
|
||||
"Entity has a Box Shape component",
|
||||
"Blender Configuration|Vegetation Areas: SUCCESS",
|
||||
"Blender Box Shape|Box Configuration|Dimensions: SUCCESS",
|
||||
"Camera entity created",
|
||||
"LayerBlender_E2E_Editor: result=SUCCESS"
|
||||
]
|
||||
|
||||
@@ -85,12 +84,11 @@ class TestLayerBlender(object):
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.xfail
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows'])
|
||||
def test_LayerBlender_E2E_Launcher(self, workspace, project, launcher, level, remote_console_instance,
|
||||
launcher_platform):
|
||||
|
||||
launcher.args.extend(["-NullRenderer"])
|
||||
launcher.args.extend(["-rhi=Null"])
|
||||
launcher.start()
|
||||
assert launcher.is_alive(), "Launcher failed to start"
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ class TestLayerSpawner(object):
|
||||
@pytest.mark.test_case_id("C30000751")
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@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):
|
||||
|
||||
expected_lines = [
|
||||
@@ -136,5 +136,6 @@ class TestLayerSpawner(object):
|
||||
editor,
|
||||
"LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py",
|
||||
expected_lines,
|
||||
cfg_args=[level]
|
||||
cfg_args=[level],
|
||||
null_renderer=False
|
||||
)
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z
|
||||
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
|
||||
mesh_asset_path = os.path.join("models", "sphere.azmodel")
|
||||
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():
|
||||
print(f"'{surface_entity.name}' created")
|
||||
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
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -742,14 +742,14 @@
|
||||
</Class>
|
||||
<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="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="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}">
|
||||
<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>
|
||||
</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 name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
|
||||
@@ -1045,14 +1045,14 @@
|
||||
</Class>
|
||||
<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="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="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}">
|
||||
<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>
|
||||
</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 name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
|
||||
@@ -1085,14 +1085,14 @@
|
||||
</Class>
|
||||
<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="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="resultSlotIDs" type="{D0B13803-101B-54D8-914C-0DA49FDFA268}">
|
||||
<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>
|
||||
</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 name="bool" field="IsDependencyReady" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
|
||||
@@ -1896,7 +1896,7 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
|
||||
|
||||
if (m_pressedKeyState != KeyPressedState::PressedInPreviousFrame)
|
||||
{
|
||||
CUndo undo("Move Camera");
|
||||
AzToolsFramework::ScopedUndoBatch undo("Move Camera");
|
||||
if (bMoveOnly)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
CUndo undo("Move Camera");
|
||||
AzToolsFramework::ScopedUndoBatch undo("Move Camera");
|
||||
if (bMoveOnly)
|
||||
{
|
||||
AZ::TransformBus::Event(
|
||||
@@ -1945,6 +1945,8 @@ void EditorViewportWidget::SetViewTM(const Matrix34& viewTM, bool bMoveOnly)
|
||||
m_viewEntityId, &AZ::TransformInterface::SetWorldTM,
|
||||
LYTransformToAZTransform(camMatrix));
|
||||
}
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::AddDirtyEntity, m_viewEntityId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.Amazon.Lumberyard.Editor</string>
|
||||
<string>org.O3DE.Editor</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
|
||||
@@ -46,4 +46,8 @@ ly_add_target(
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AzQtComponents
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AzQtComponents
|
||||
)
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
#include "ValidationHandler.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/ReflectedPropertyEditor.hxx>
|
||||
#include <AzToolsFramework/UI/UICore/WidgetHelpers.h>
|
||||
#include <Util/FileUtil.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QCloseEvent>
|
||||
@@ -52,7 +52,7 @@ namespace ProjectSettingsTool
|
||||
PlatformEnabled(PlatformId::Ios) ?
|
||||
ProjectSettingsContainer::PlistInitVector({
|
||||
ProjectSettingsContainer::PlatformAndPath
|
||||
{ PlatformId::Ios, m_projectRoot + PlatformResourcesFolder(PlatformId::Ios) }
|
||||
{ PlatformId::Ios, GetPlatformResource(PlatformId::Ios) }
|
||||
})
|
||||
:
|
||||
ProjectSettingsContainer::PlistInitVector())
|
||||
@@ -647,33 +647,38 @@ namespace ProjectSettingsTool
|
||||
// iOS can be disabled if the plist file is missing
|
||||
if (platformId == PlatformId::Ios)
|
||||
{
|
||||
const AZStd::string filename = m_projectRoot + PlatformResourcesFolder(platformId);
|
||||
return CFileUtil::FileExists(filename.c_str());
|
||||
AZStd::string plistPath = GetPlatformResource(platformId);
|
||||
return !plistPath.empty();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ProjectSettingsToolWindow::PlatformResourcesFolder(PlatformId platformId)
|
||||
AZStd::string ProjectSettingsToolWindow::GetPlatformResource(PlatformId platformId)
|
||||
{
|
||||
if (platformId == PlatformId::Ios)
|
||||
{
|
||||
const AZStd::string firstfilename = m_projectRoot + "/Gem/Resources/Platform/iOS/Info.plist";
|
||||
if (CFileUtil::FileExists(firstfilename.c_str()))
|
||||
const char* searchPaths[] = {
|
||||
"Resources/Platform/iOS/Info.plist",
|
||||
|
||||
// legacy paths
|
||||
"Gem/Resources/Platform/iOS/Info.plist",
|
||||
"Gem/Resources/IOSLauncher/Info.plist",
|
||||
};
|
||||
|
||||
for (auto relPath : searchPaths)
|
||||
{
|
||||
return "/Gem/Resources/Platform/iOS/Info.plist";
|
||||
}
|
||||
else
|
||||
{
|
||||
const AZStd::string filename = m_projectRoot + "/Gem/Resources/IOSLauncher/Info.plist";
|
||||
if (CFileUtil::FileExists(filename.c_str()))
|
||||
AZ::IO::FixedMaxPath projectPlist{ m_projectRoot };
|
||||
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>
|
||||
|
||||
@@ -137,8 +137,8 @@ namespace ProjectSettingsTool
|
||||
// returns true if the platform is enabled
|
||||
bool PlatformEnabled(PlatformId platformId);
|
||||
|
||||
// returns the resource folder
|
||||
const char* PlatformResourcesFolder(PlatformId platformId);
|
||||
// returns the main platform specific resource file e.g. for iOS it would be the Info.plist
|
||||
AZStd::string GetPlatformResource(PlatformId platformId);
|
||||
|
||||
// The ui for the window
|
||||
QScopedPointer<Ui::ProjectSettingsToolWidget> m_ui;
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace AZ
|
||||
{
|
||||
const char* uuidString = nullptr;
|
||||
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));
|
||||
}
|
||||
|
||||
+25
-5
@@ -205,6 +205,25 @@ namespace AzFramework
|
||||
class InputDeviceImplementationRequest : public AZ::EBusTraits
|
||||
{
|
||||
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
|
||||
using Bus = AZ::EBus<InputDeviceImplementationRequest<InputDeviceType>>;
|
||||
@@ -214,11 +233,12 @@ namespace AzFramework
|
||||
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
|
||||
//! device implementation, while passing nullptr will delete any existing 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)
|
||||
: 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&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//! \ref InputDeviceImplementationRequest<InputDeviceType>::CreateCustomImplementation
|
||||
AZ_INLINE void CreateCustomImplementation(CreateFunctionType createFunction) override
|
||||
//! \ref InputDeviceImplementationRequest<InputDeviceType>::SetCustomImplementation
|
||||
AZ_INLINE void SetCustomImplementation(CreateFunctionType createFunction) override
|
||||
{
|
||||
AZStd::unique_ptr<typename InputDeviceType::Implementation> newImplementation;
|
||||
if (createFunction)
|
||||
|
||||
@@ -63,6 +63,9 @@ namespace AzToolsFramework
|
||||
//! Signal the Python handler to stop
|
||||
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)
|
||||
virtual void WaitForInitialization() {}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
|
||||
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -31,6 +33,12 @@ namespace AZ
|
||||
{
|
||||
serializeContext->Class<ExportingComponent, AZ::Component>()->Version(2);
|
||||
}
|
||||
|
||||
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
Events::ExportProductList::Reflect(behaviorContext);
|
||||
}
|
||||
}
|
||||
} // namespace SceneCore
|
||||
} // namespace SceneAPI
|
||||
|
||||
@@ -211,6 +211,7 @@ namespace AZ
|
||||
AZ::SceneAPI::Containers::SceneGraph::Reflect(context);
|
||||
AZ::SceneAPI::Containers::SceneManifest::Reflect(context);
|
||||
AZ::SceneAPI::Containers::RuleContainer::Reflect(context);
|
||||
AZ::SceneAPI::SceneCore::ExportingComponent::Reflect(context);
|
||||
}
|
||||
|
||||
void Activate()
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/std/limits.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -49,6 +51,45 @@ namespace AZ
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ExportProductList::Reflect(ReflectContext* context)
|
||||
{
|
||||
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<ExportProduct>()->Version(1);
|
||||
serializeContext->Class<ExportProductList>()->Version(1);
|
||||
}
|
||||
|
||||
if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<ExportProduct>("ExportProduct")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "scene")
|
||||
->Property("filename", BehaviorValueProperty(&ExportProduct::m_filename))
|
||||
->Property("sourceId", BehaviorValueProperty(&ExportProduct::m_id))
|
||||
->Property("assetType", BehaviorValueProperty(&ExportProduct::m_assetType))
|
||||
->Property("productDependencies", BehaviorValueProperty(&ExportProduct::m_productDependencies))
|
||||
->Property("subId",
|
||||
[](ExportProduct* self) { return self->m_subId.has_value() ? self->m_subId.value() : 0; },
|
||||
[](ExportProduct* self, u32 subId) { self->m_subId = AZStd::optional<u32>(subId); });
|
||||
|
||||
behaviorContext->Class<ExportProductList>("ExportProductList")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "scene")
|
||||
->Method("AddProduct", [](ExportProductList& self, ExportProduct& product)
|
||||
{
|
||||
self.AddProduct(
|
||||
product.m_filename,
|
||||
product.m_id,
|
||||
product.m_assetType,
|
||||
product.m_lod,
|
||||
product.m_subId,
|
||||
product.m_dependencyFlags);
|
||||
})
|
||||
->Method("GetProducts", &ExportProductList::GetProducts)
|
||||
->Method("AddDependencyToProduct", &ExportProductList::AddDependencyToProduct);
|
||||
}
|
||||
}
|
||||
|
||||
ExportProduct& ExportProductList::AddProduct(const AZStd::string& filename, Uuid id, Data::AssetType assetType, AZStd::optional<u8> lod, AZStd::optional<u32> subId,
|
||||
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class ReflectContext;
|
||||
|
||||
namespace SceneAPI
|
||||
{
|
||||
namespace Events
|
||||
@@ -24,6 +26,7 @@ namespace AZ
|
||||
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags = Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad));
|
||||
SCENE_CORE_API ExportProduct(AZStd::string&& filename, Uuid id, Data::AssetType assetType, AZStd::optional<u8> lod, AZStd::optional<u32> subId,
|
||||
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags = Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad));
|
||||
ExportProduct() = default;
|
||||
ExportProduct(const ExportProduct& rhs) = default;
|
||||
SCENE_CORE_API ExportProduct(ExportProduct&& rhs);
|
||||
|
||||
@@ -54,6 +57,8 @@ namespace AZ
|
||||
class ExportProductList
|
||||
{
|
||||
public:
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
SCENE_CORE_API ExportProduct& AddProduct(const AZStd::string& filename, Uuid id, Data::AssetType assetType, AZStd::optional<u8> lod, AZStd::optional<u32> subId,
|
||||
Data::ProductDependencyInfo::ProductDependencyFlags dependencyFlags = Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad));
|
||||
SCENE_CORE_API ExportProduct& AddProduct(AZStd::string&& filename, Uuid id, Data::AssetType assetType, AZStd::optional<u8> lod, AZStd::optional<u32> subId,
|
||||
@@ -69,3 +74,9 @@ namespace AZ
|
||||
} // namespace Events
|
||||
} // namespace SceneAPI
|
||||
} // namespace AZ
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
AZ_TYPE_INFO_SPECIALIZE(SceneAPI::Events::ExportProduct, "{6054EDCB-4C04-4D96-BF26-704999FFB725}");
|
||||
AZ_TYPE_INFO_SPECIALIZE(SceneAPI::Events::ExportProductList, "{1C76A51F-431B-4987-B653-CFCC940D0D0F}");
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/IO/SystemFile.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <SceneAPI/SceneCore/Import/ManifestImportRequestHandler.h>
|
||||
@@ -75,15 +76,16 @@ namespace AZ
|
||||
filename += s_extension;
|
||||
filename += s_generated;
|
||||
|
||||
AZStd::string altManifestPath = path;
|
||||
AZStd::string altManifestFolder = path;
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(
|
||||
&AzFramework::ApplicationRequests::Bus::Events::MakePathRootRelative,
|
||||
altManifestPath);
|
||||
&AzFramework::ApplicationRequests::Bus::Events::MakePathRelative,
|
||||
altManifestFolder,
|
||||
AZ::Utils::GetProjectPath().c_str());
|
||||
|
||||
AZ::StringFunc::Path::GetFolderPath(altManifestPath.c_str(), altManifestPath);
|
||||
AZ::StringFunc::Path::GetFolderPath(altManifestFolder.c_str(), altManifestFolder);
|
||||
|
||||
AZStd::string generatedAssetInfoPath;
|
||||
AZ::StringFunc::Path::Join(assetCacheRoot.c_str(), altManifestPath.c_str(), generatedAssetInfoPath);
|
||||
AZ::StringFunc::Path::Join(assetCacheRoot.c_str(), altManifestFolder.c_str(), generatedAssetInfoPath);
|
||||
AZ::StringFunc::Path::ConstructFull(generatedAssetInfoPath.c_str(), filename.c_str(), generatedAssetInfoPath);
|
||||
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Exists(generatedAssetInfoPath.c_str()))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,213 +25,319 @@
|
||||
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
|
||||
#include <SceneAPI/SceneData/Rules/ScriptProcessorRule.h>
|
||||
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
|
||||
#include <SceneAPI/SceneCore/Events/ExportProductList.h>
|
||||
|
||||
namespace AZ
|
||||
namespace AZ::SceneAPI::Behaviors
|
||||
{
|
||||
namespace SceneAPI
|
||||
class EditorPythonConsoleNotificationHandler final
|
||||
: protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
|
||||
{
|
||||
namespace Behaviors
|
||||
public:
|
||||
EditorPythonConsoleNotificationHandler()
|
||||
{
|
||||
class EditorPythonConsoleNotificationHandler final
|
||||
: protected AzToolsFramework::EditorPythonConsoleNotificationBus::Handler
|
||||
BusConnect();
|
||||
}
|
||||
|
||||
~EditorPythonConsoleNotificationHandler()
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AzToolsFramework::EditorPythonConsoleNotifications
|
||||
void OnTraceMessage([[maybe_unused]] AZStd::string_view message) override
|
||||
{
|
||||
using namespace AZ::SceneAPI::Utilities;
|
||||
AZ_TracePrintf(LogWindow, "%.*s \n", AZ_STRING_ARG(message));
|
||||
}
|
||||
|
||||
void OnErrorMessage([[maybe_unused]] AZStd::string_view message) override
|
||||
{
|
||||
using namespace AZ::SceneAPI::Utilities;
|
||||
AZ_TracePrintf(ErrorWindow, "[ERROR] %.*s \n", AZ_STRING_ARG(message));
|
||||
}
|
||||
|
||||
void OnExceptionMessage([[maybe_unused]] AZStd::string_view message) override
|
||||
{
|
||||
using namespace AZ::SceneAPI::Utilities;
|
||||
AZ_TracePrintf(ErrorWindow, "[EXCEPTION] %.*s \n", AZ_STRING_ARG(message));
|
||||
}
|
||||
};
|
||||
|
||||
using ExportProductList = AZ::SceneAPI::Events::ExportProductList;
|
||||
|
||||
// a event bus to signal during scene building
|
||||
struct ScriptBuildingNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
virtual AZStd::string OnUpdateManifest(Containers::Scene& scene) = 0;
|
||||
virtual ExportProductList OnPrepareForExport(
|
||||
const Containers::Scene& scene,
|
||||
AZStd::string_view outputDirectory,
|
||||
AZStd::string_view platformIdentifier,
|
||||
const ExportProductList& productList) = 0;
|
||||
};
|
||||
using ScriptBuildingNotificationBus = AZ::EBus<ScriptBuildingNotifications>;
|
||||
|
||||
// a back end to handle scene builder events for a script
|
||||
struct ScriptBuildingNotificationBusHandler final
|
||||
: public ScriptBuildingNotificationBus::Handler
|
||||
, public AZ::BehaviorEBusHandler
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(
|
||||
ScriptBuildingNotificationBusHandler,
|
||||
"{DF2B51DE-A4D0-4139-B5D0-DF185832380D}",
|
||||
AZ::SystemAllocator,
|
||||
OnUpdateManifest,
|
||||
OnPrepareForExport);
|
||||
|
||||
virtual ~ScriptBuildingNotificationBusHandler() = default;
|
||||
|
||||
AZStd::string OnUpdateManifest(Containers::Scene& scene) override
|
||||
{
|
||||
AZStd::string result;
|
||||
CallResult(result, FN_OnUpdateManifest, scene);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExportProductList OnPrepareForExport(
|
||||
const Containers::Scene& scene,
|
||||
AZStd::string_view outputDirectory,
|
||||
AZStd::string_view platformIdentifier,
|
||||
const ExportProductList& productList) override
|
||||
{
|
||||
ExportProductList result;
|
||||
CallResult(result, FN_OnPrepareForExport, scene, outputDirectory, platformIdentifier, productList);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
public:
|
||||
EditorPythonConsoleNotificationHandler()
|
||||
{
|
||||
BusConnect();
|
||||
}
|
||||
behaviorContext->EBus<ScriptBuildingNotificationBus>("ScriptBuildingNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "scene")
|
||||
->Handler<ScriptBuildingNotificationBusHandler>()
|
||||
->Event("OnUpdateManifest", &ScriptBuildingNotificationBus::Events::OnUpdateManifest)
|
||||
->Event("OnPrepareForExport", &ScriptBuildingNotificationBus::Events::OnPrepareForExport);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
~EditorPythonConsoleNotificationHandler()
|
||||
{
|
||||
BusDisconnect();
|
||||
}
|
||||
struct ScriptProcessorRuleBehavior::ExportEventHandler final
|
||||
: public AZ::SceneAPI::SceneCore::ExportingComponent
|
||||
{
|
||||
using PreExportEventContextFunction = AZStd::function<bool(Events::PreExportEventContext&)>;
|
||||
PreExportEventContextFunction m_preExportEventContextFunction;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AzToolsFramework::EditorPythonConsoleNotifications
|
||||
void OnTraceMessage([[maybe_unused]] AZStd::string_view message) override
|
||||
{
|
||||
using namespace AZ::SceneAPI::Utilities;
|
||||
AZ_TracePrintf(LogWindow, "%.*s \n", AZ_STRING_ARG(message));
|
||||
}
|
||||
ExportEventHandler(PreExportEventContextFunction preExportEventContextFunction)
|
||||
: m_preExportEventContextFunction(preExportEventContextFunction)
|
||||
{
|
||||
BindToCall(&ExportEventHandler::PrepareForExport);
|
||||
AZ::SceneAPI::SceneCore::ExportingComponent::Activate();
|
||||
}
|
||||
|
||||
void OnErrorMessage([[maybe_unused]] AZStd::string_view message) override
|
||||
{
|
||||
using namespace AZ::SceneAPI::Utilities;
|
||||
AZ_TracePrintf(ErrorWindow, "[ERROR] %.*s \n", AZ_STRING_ARG(message));
|
||||
}
|
||||
~ExportEventHandler()
|
||||
{
|
||||
AZ::SceneAPI::SceneCore::ExportingComponent::Deactivate();
|
||||
}
|
||||
|
||||
void OnExceptionMessage([[maybe_unused]] AZStd::string_view message) override
|
||||
{
|
||||
using namespace AZ::SceneAPI::Utilities;
|
||||
AZ_TracePrintf(ErrorWindow, "[EXCEPTION] %.*s \n", AZ_STRING_ARG(message));
|
||||
}
|
||||
};
|
||||
// this allows a Python script to add product assets on "scene export"
|
||||
Events::ProcessingResult PrepareForExport(Events::PreExportEventContext& context)
|
||||
{
|
||||
return m_preExportEventContextFunction(context) ? Events::ProcessingResult::Success : Events::ProcessingResult::Failure;
|
||||
}
|
||||
};
|
||||
|
||||
// a event bus to signal during scene building
|
||||
struct ScriptBuildingNotifications
|
||||
: public AZ::EBusTraits
|
||||
void ScriptProcessorRuleBehavior::Activate()
|
||||
{
|
||||
Events::AssetImportRequestBus::Handler::BusConnect();
|
||||
m_exportEventHandler = AZStd::make_shared<ExportEventHandler>([this](Events::PreExportEventContext& context)
|
||||
{
|
||||
return this->DoPrepareForExport(context);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptProcessorRuleBehavior::Deactivate()
|
||||
{
|
||||
m_exportEventHandler.reset();
|
||||
Events::AssetImportRequestBus::Handler::BusDisconnect();
|
||||
UnloadPython();
|
||||
}
|
||||
|
||||
bool ScriptProcessorRuleBehavior::LoadPython(const AZ::SceneAPI::Containers::Scene& scene)
|
||||
{
|
||||
if (m_editorPythonEventsInterface && !m_scriptFilename.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// get project folder
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
AZ::IO::FixedMaxPath projectPath;
|
||||
if (!settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const AZ::SceneAPI::Containers::SceneManifest& manifest = scene.GetManifest();
|
||||
auto view = Containers::MakeDerivedFilterView<DataTypes::IScriptProcessorRule>(manifest.GetValueStorage());
|
||||
for (const auto& scriptItem : view)
|
||||
{
|
||||
AZ::IO::FixedMaxPath scriptFilename(scriptItem.GetScriptFilename());
|
||||
if (scriptFilename.empty())
|
||||
{
|
||||
virtual AZStd::string OnUpdateManifest(Containers::Scene& scene) = 0;
|
||||
};
|
||||
using ScriptBuildingNotificationBus = AZ::EBus<ScriptBuildingNotifications>;
|
||||
AZ_Warning("scene", false, "Skipping an empty script filename in (%s)", scene.GetManifestFilename().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// a back end to handle scene builder events for a script
|
||||
struct ScriptBuildingNotificationBusHandler final
|
||||
: public ScriptBuildingNotificationBus::Handler
|
||||
, public AZ::BehaviorEBusHandler
|
||||
// check for file exist via absolute path
|
||||
if (!IO::FileIOBase::GetInstance()->Exists(scriptFilename.c_str()))
|
||||
{
|
||||
AZ_EBUS_BEHAVIOR_BINDER(
|
||||
ScriptBuildingNotificationBusHandler,
|
||||
"{DF2B51DE-A4D0-4139-B5D0-DF185832380D}",
|
||||
AZ::SystemAllocator,
|
||||
OnUpdateManifest);
|
||||
|
||||
virtual ~ScriptBuildingNotificationBusHandler() = default;
|
||||
|
||||
AZStd::string OnUpdateManifest(Containers::Scene& scene) override
|
||||
// check for script in the project folder
|
||||
AZ::IO::FixedMaxPath projectScriptPath = projectPath / scriptFilename;
|
||||
if (!IO::FileIOBase::GetInstance()->Exists(projectScriptPath.c_str()))
|
||||
{
|
||||
AZStd::string result;
|
||||
CallResult(result, FN_OnUpdateManifest, scene);
|
||||
return result;
|
||||
AZ_Warning("scene", false, "Skipping a missing script (%s) in manifest file (%s)",
|
||||
scriptFilename.c_str(),
|
||||
scene.GetManifestFilename().c_str());
|
||||
continue;
|
||||
}
|
||||
scriptFilename = AZStd::move(projectScriptPath);
|
||||
}
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
// lazy load the Python interface
|
||||
auto editorPythonEventsInterface = AZ::Interface<AzToolsFramework::EditorPythonEventsInterface>::Get();
|
||||
if (editorPythonEventsInterface->IsPythonActive() == false)
|
||||
{
|
||||
const bool silenceWarnings = false;
|
||||
if (editorPythonEventsInterface->StartPython(silenceWarnings) == false)
|
||||
{
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<ScriptBuildingNotificationBus>("ScriptBuildingNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "scene")
|
||||
->Handler<ScriptBuildingNotificationBusHandler>()
|
||||
->Event("OnUpdateManifest", &ScriptBuildingNotificationBus::Events::OnUpdateManifest);
|
||||
}
|
||||
editorPythonEventsInterface = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// both Python and the script need to be ready
|
||||
if (editorPythonEventsInterface == nullptr || scriptFilename.empty())
|
||||
{
|
||||
AZ_Warning("scene", false,"The scene manifest (%s) attempted to use script(%s) but Python is not enabled;"
|
||||
"please add the EditorPythonBinding gem & PythonAssetBuilder gem to your project.",
|
||||
scene.GetManifestFilename().c_str(), scriptFilename.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_editorPythonEventsInterface = editorPythonEventsInterface;
|
||||
m_scriptFilename = scriptFilename.c_str();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptProcessorRuleBehavior::UnloadPython()
|
||||
{
|
||||
if (m_editorPythonEventsInterface)
|
||||
{
|
||||
const bool silenceWarnings = true;
|
||||
m_editorPythonEventsInterface->StopPython(silenceWarnings);
|
||||
m_editorPythonEventsInterface = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptProcessorRuleBehavior::DoPrepareForExport(Events::PreExportEventContext& context)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
auto executeCallback = [this, &context]()
|
||||
{
|
||||
// set up script's hook callback
|
||||
EditorPythonRunnerRequestBus::Broadcast(&EditorPythonRunnerRequestBus::Events::ExecuteByFilename,
|
||||
m_scriptFilename.c_str());
|
||||
|
||||
// call script's callback to allow extra products
|
||||
ExportProductList extraProducts;
|
||||
ScriptBuildingNotificationBus::BroadcastResult(extraProducts, &ScriptBuildingNotificationBus::Events::OnPrepareForExport,
|
||||
context.GetScene(),
|
||||
context.GetOutputDirectory(),
|
||||
context.GetPlatformIdentifier(),
|
||||
context.GetProductList()
|
||||
);
|
||||
|
||||
// add new products
|
||||
for (const auto& product : extraProducts.GetProducts())
|
||||
{
|
||||
context.GetProductList().AddProduct(
|
||||
product.m_filename,
|
||||
product.m_id,
|
||||
product.m_assetType,
|
||||
product.m_lod,
|
||||
product.m_subId,
|
||||
product.m_dependencyFlags);
|
||||
}
|
||||
};
|
||||
|
||||
if (LoadPython(context.GetScene()))
|
||||
{
|
||||
EditorPythonConsoleNotificationHandler logger;
|
||||
m_editorPythonEventsInterface->ExecuteWithLock(executeCallback);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptProcessorRuleBehavior::Reflect(ReflectContext* context)
|
||||
{
|
||||
ScriptBuildingNotificationBusHandler::Reflect(context);
|
||||
|
||||
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<ScriptProcessorRuleBehavior, BehaviorComponent>()->Version(1);
|
||||
}
|
||||
}
|
||||
|
||||
Events::ProcessingResult ScriptProcessorRuleBehavior::UpdateManifest(
|
||||
Containers::Scene& scene,
|
||||
Events::AssetImportRequest::ManifestAction action,
|
||||
[[maybe_unused]] Events::AssetImportRequest::RequestingApplication requester)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
if (action != ManifestAction::Update)
|
||||
{
|
||||
return Events::ProcessingResult::Ignored;
|
||||
}
|
||||
|
||||
if (LoadPython(scene))
|
||||
{
|
||||
AZStd::string manifestUpdate;
|
||||
auto executeCallback = [this, &scene, &manifestUpdate]()
|
||||
{
|
||||
EditorPythonRunnerRequestBus::Broadcast(&EditorPythonRunnerRequestBus::Events::ExecuteByFilename,
|
||||
m_scriptFilename.c_str());
|
||||
|
||||
ScriptBuildingNotificationBus::BroadcastResult(manifestUpdate, &ScriptBuildingNotificationBus::Events::OnUpdateManifest,
|
||||
scene);
|
||||
};
|
||||
|
||||
void ScriptProcessorRuleBehavior::Activate()
|
||||
EditorPythonConsoleNotificationHandler logger;
|
||||
m_editorPythonEventsInterface->ExecuteWithLock(executeCallback);
|
||||
|
||||
// attempt to load the manifest string back to a JSON-scene-manifest
|
||||
auto sceneManifestLoader = AZStd::make_unique<AZ::SceneAPI::Containers::SceneManifest>();
|
||||
auto loadOutcome = sceneManifestLoader->LoadFromString(manifestUpdate);
|
||||
if (loadOutcome.IsSuccess())
|
||||
{
|
||||
Events::AssetImportRequestBus::Handler::BusConnect();
|
||||
scene.GetManifest().Clear();
|
||||
for (size_t entryIndex = 0; entryIndex < sceneManifestLoader->GetEntryCount(); ++entryIndex)
|
||||
{
|
||||
scene.GetManifest().AddEntry(sceneManifestLoader->GetValue(entryIndex));
|
||||
}
|
||||
return Events::ProcessingResult::Success;
|
||||
}
|
||||
}
|
||||
return Events::ProcessingResult::Ignored;
|
||||
}
|
||||
|
||||
void ScriptProcessorRuleBehavior::Deactivate()
|
||||
{
|
||||
Events::AssetImportRequestBus::Handler::BusDisconnect();
|
||||
if (m_editorPythonEventsInterface)
|
||||
{
|
||||
const bool silenceWarnings = true;
|
||||
m_editorPythonEventsInterface->StopPython(silenceWarnings);
|
||||
m_editorPythonEventsInterface = nullptr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptProcessorRuleBehavior::Reflect(ReflectContext* context)
|
||||
{
|
||||
ScriptBuildingNotificationBusHandler::Reflect(context);
|
||||
|
||||
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->Class<ScriptProcessorRuleBehavior, BehaviorComponent>()->Version(1);
|
||||
}
|
||||
}
|
||||
|
||||
Events::ProcessingResult ScriptProcessorRuleBehavior::UpdateManifest(
|
||||
Containers::Scene& scene,
|
||||
Events::AssetImportRequest::ManifestAction action,
|
||||
[[maybe_unused]] Events::AssetImportRequest::RequestingApplication requester)
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
|
||||
if (action != ManifestAction::Update)
|
||||
{
|
||||
return Events::ProcessingResult::Ignored;
|
||||
}
|
||||
|
||||
// get project folder
|
||||
auto settingsRegistry = AZ::SettingsRegistry::Get();
|
||||
AZ::IO::FixedMaxPath projectPath;
|
||||
if (!settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath))
|
||||
{
|
||||
return Events::ProcessingResult::Ignored;
|
||||
}
|
||||
|
||||
auto& sceneManifest = scene.GetManifest();
|
||||
auto view = Containers::MakeDerivedFilterView<DataTypes::IScriptProcessorRule>(sceneManifest.GetValueStorage());
|
||||
for (const auto& scriptItem : view)
|
||||
{
|
||||
AZ::IO::FixedMaxPath scriptFilename(scriptItem.GetScriptFilename());
|
||||
if (scriptFilename.empty())
|
||||
{
|
||||
AZ_Warning("scene", false, "Skipping an empty script filename in (%s)", scene.GetManifestFilename().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for file exist via absolute path
|
||||
if (!IO::FileIOBase::GetInstance()->Exists(scriptFilename.c_str()))
|
||||
{
|
||||
// check for script in the project folder
|
||||
AZ::IO::FixedMaxPath projectScriptPath = projectPath / scriptFilename;
|
||||
if (!IO::FileIOBase::GetInstance()->Exists(projectScriptPath.c_str()))
|
||||
{
|
||||
AZ_Warning("scene", false, "Skipping a missing script (%s) in manifest file (%s)",
|
||||
scriptFilename.c_str(),
|
||||
scene.GetManifestFilename().c_str());
|
||||
|
||||
continue;
|
||||
}
|
||||
scriptFilename = AZStd::move(projectScriptPath);
|
||||
}
|
||||
|
||||
// lazy load the Python interface
|
||||
if (!m_editorPythonEventsInterface)
|
||||
{
|
||||
m_editorPythonEventsInterface = AZ::Interface<AzToolsFramework::EditorPythonEventsInterface>::Get();
|
||||
const bool silenceWarnings = true;
|
||||
m_editorPythonEventsInterface->StartPython(silenceWarnings);
|
||||
}
|
||||
|
||||
if (!m_editorPythonEventsInterface && !scriptFilename.empty())
|
||||
{
|
||||
AZ_Warning("scene", false,
|
||||
"The scene manifest (%s) attempted to use script(%s) but Python is not enabled;"
|
||||
"please add the EditorPythonBinding gem & PythonAssetBuilder gem to your project.",
|
||||
scene.GetManifestFilename().c_str(), scriptFilename.c_str());
|
||||
|
||||
return Events::ProcessingResult::Ignored;
|
||||
}
|
||||
|
||||
AZStd::string manifestUpdate;
|
||||
auto executeCallback = [&scene, &scriptFilename, &manifestUpdate]()
|
||||
{
|
||||
EditorPythonRunnerRequestBus::Broadcast(
|
||||
&EditorPythonRunnerRequestBus::Events::ExecuteByFilename,
|
||||
scriptFilename.c_str());
|
||||
|
||||
ScriptBuildingNotificationBus::BroadcastResult(
|
||||
manifestUpdate,
|
||||
&ScriptBuildingNotificationBus::Events::OnUpdateManifest,
|
||||
scene);
|
||||
};
|
||||
EditorPythonConsoleNotificationHandler logger;
|
||||
m_editorPythonEventsInterface->ExecuteWithLock(executeCallback);
|
||||
|
||||
// attempt to load the manifest string back to a JSON-scene-manifest
|
||||
auto sceneManifestLoader = AZStd::make_unique<AZ::SceneAPI::Containers::SceneManifest>();
|
||||
auto loadOutcome = sceneManifestLoader->LoadFromString(manifestUpdate);
|
||||
if (loadOutcome.IsSuccess())
|
||||
{
|
||||
sceneManifest.Clear();
|
||||
for (size_t entryIndex = 0; entryIndex < sceneManifestLoader->GetEntryCount(); ++entryIndex)
|
||||
{
|
||||
sceneManifest.AddEntry(sceneManifestLoader->GetValue(entryIndex));
|
||||
}
|
||||
return Events::ProcessingResult::Success;
|
||||
}
|
||||
}
|
||||
return Events::ProcessingResult::Ignored;
|
||||
}
|
||||
|
||||
} // namespace Behaviors
|
||||
} // namespace SceneAPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -11,40 +11,56 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <SceneAPI/SceneCore/Components/BehaviorComponent.h>
|
||||
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
|
||||
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
|
||||
#include <SceneAPI/SceneCore/Events/ExportEventContext.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class EditorPythonEventsInterface;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
namespace AZ::SceneAPI::Events
|
||||
{
|
||||
namespace SceneAPI
|
||||
class PreExportEventContext;
|
||||
}
|
||||
|
||||
namespace AZ::SceneAPI::Containers
|
||||
{
|
||||
class Scene;
|
||||
}
|
||||
|
||||
namespace AZ::SceneAPI::Behaviors
|
||||
{
|
||||
class SCENE_DATA_CLASS ScriptProcessorRuleBehavior
|
||||
: public SceneCore::BehaviorComponent
|
||||
, public Events::AssetImportRequestBus::Handler
|
||||
{
|
||||
namespace Behaviors
|
||||
{
|
||||
class SCENE_DATA_CLASS ScriptProcessorRuleBehavior
|
||||
: public SceneCore::BehaviorComponent
|
||||
, public Events::AssetImportRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(ScriptProcessorRuleBehavior, "{24054E73-1B92-43B0-AC13-174B2F0E3F66}", SceneCore::BehaviorComponent);
|
||||
public:
|
||||
AZ_COMPONENT(ScriptProcessorRuleBehavior, "{24054E73-1B92-43B0-AC13-174B2F0E3F66}", SceneCore::BehaviorComponent);
|
||||
|
||||
~ScriptProcessorRuleBehavior() override = default;
|
||||
~ScriptProcessorRuleBehavior() override = default;
|
||||
|
||||
SCENE_DATA_API void Activate() override;
|
||||
SCENE_DATA_API void Deactivate() override;
|
||||
static void Reflect(ReflectContext* context);
|
||||
SCENE_DATA_API void Activate() override;
|
||||
SCENE_DATA_API void Deactivate() override;
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
// AssetImportRequestBus::Handler
|
||||
SCENE_DATA_API Events::ProcessingResult UpdateManifest(
|
||||
Containers::Scene& scene,
|
||||
ManifestAction action,
|
||||
RequestingApplication requester) override;
|
||||
// AssetImportRequestBus::Handler
|
||||
SCENE_DATA_API Events::ProcessingResult UpdateManifest(
|
||||
Containers::Scene& scene,
|
||||
ManifestAction action,
|
||||
RequestingApplication requester) override;
|
||||
|
||||
private:
|
||||
AzToolsFramework::EditorPythonEventsInterface* m_editorPythonEventsInterface = nullptr;
|
||||
};
|
||||
} // namespace SceneData
|
||||
} // namespace SceneAPI
|
||||
} // namespace AZ
|
||||
|
||||
protected:
|
||||
bool LoadPython(const AZ::SceneAPI::Containers::Scene& scene);
|
||||
void UnloadPython();
|
||||
bool DoPrepareForExport(Events::PreExportEventContext& context);
|
||||
|
||||
private:
|
||||
AzToolsFramework::EditorPythonEventsInterface* m_editorPythonEventsInterface = nullptr;
|
||||
AZStd::string m_scriptFilename;
|
||||
|
||||
struct ExportEventHandler;
|
||||
AZStd::shared_ptr<ExportEventHandler> m_exportEventHandler;
|
||||
};
|
||||
} // namespace AZ::SceneAPI::Behaviors
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class BehaviorContext;
|
||||
class EditContext;
|
||||
class SerializeContext;
|
||||
} // namespace AZ
|
||||
|
||||
// this just provides a convenient template to avoid the necessary boilerplate when you derive from AWSScriptBehaviorBase
|
||||
#define AWS_SCRIPT_BEHAVIOR_DEFINITION(className, guidString) \
|
||||
AZ_TYPE_INFO(className, guidString) \
|
||||
AZ_CLASS_ALLOCATOR(className, AZ::SystemAllocator, 0) \
|
||||
void ReflectSerialization(AZ::SerializeContext* serializeContext) override; \
|
||||
void ReflectBehaviors(AZ::BehaviorContext* behaviorContext) override; \
|
||||
void ReflectEditParameters(AZ::EditContext* editContext) override; \
|
||||
className(); \
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! An interface for AWS ScriptCanvas Behaviors to inherit from
|
||||
class AWSScriptBehaviorBase
|
||||
{
|
||||
public:
|
||||
virtual ~AWSScriptBehaviorBase() = default;
|
||||
|
||||
virtual void ReflectSerialization(AZ::SerializeContext* reflectContext) = 0;
|
||||
virtual void ReflectBehaviors(AZ::BehaviorContext* behaviorContext) = 0;
|
||||
virtual void ReflectEditParameters(AZ::EditContext* editContext) = 0;
|
||||
|
||||
virtual void Init() {}
|
||||
virtual void Activate() {}
|
||||
virtual void Deactivate() {}
|
||||
};
|
||||
} // namespace AWSCore
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <ScriptCanvas/AWSScriptBehaviorBase.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
using DynamoDBAttributeValueMap = AZStd::unordered_map<AZStd::string, AZStd::string>;
|
||||
@@ -55,10 +53,14 @@ namespace AWSCore
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorDynamoDB
|
||||
: public AWSScriptBehaviorBase
|
||||
{
|
||||
public:
|
||||
AWS_SCRIPT_BEHAVIOR_DEFINITION(AWSScriptBehaviorDynamoDB, "{569E74F6-1268-4199-9653-A3B603FC9F4F}");
|
||||
AZ_RTTI(AWSScriptBehaviorDynamoDB, "{569E74F6-1268-4199-9653-A3B603FC9F4F}");
|
||||
|
||||
AWSScriptBehaviorDynamoDB() = default;
|
||||
virtual ~AWSScriptBehaviorDynamoDB() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetItem(const AZStd::string& tableResourceKey, const DynamoDBAttributeValueMap& keyMap);
|
||||
static void GetItemRaw(const AZStd::string& table, const DynamoDBAttributeValueMap& keyMap, const AZStd::string& region);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <ScriptCanvas/AWSScriptBehaviorBase.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! AWS Script Behavior notifications for ScriptCanvas behaviors that interact with AWS Lambda
|
||||
@@ -53,10 +51,14 @@ namespace AWSCore
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorLambda
|
||||
: public AWSScriptBehaviorBase
|
||||
{
|
||||
public:
|
||||
AWS_SCRIPT_BEHAVIOR_DEFINITION(AWSScriptBehaviorLambda, "{9E71534D-34B3-4723-B180-2552513DDA3D}");
|
||||
AZ_RTTI(AWSScriptBehaviorLambda, "{9E71534D-34B3-4723-B180-2552513DDA3D}");
|
||||
|
||||
AWSScriptBehaviorLambda() = default;
|
||||
virtual ~AWSScriptBehaviorLambda() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void Invoke(const AZStd::string& functionResourceKey, const AZStd::string& payload);
|
||||
static void InvokeRaw(const AZStd::string& functionName, const AZStd::string& payload, const AZStd::string& region);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
#include <ScriptCanvas/AWSScriptBehaviorBase.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! AWS Script Behavior notifications for ScriptCanvas behaviors that interact with AWS S3
|
||||
@@ -68,7 +66,6 @@ namespace AWSCore
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorS3
|
||||
: public AWSScriptBehaviorBase
|
||||
{
|
||||
static constexpr const char AWSScriptBehaviorS3Name[] = "AWSScriptBehaviorS3";
|
||||
static constexpr const char OutputFileIsEmptyErrorMessage[] = "Request validation failed, output file is empty.";
|
||||
@@ -81,7 +78,12 @@ namespace AWSCore
|
||||
static constexpr const char RegionNameIsEmptyErrorMessage[] = "Request validation failed, region name is empty.";
|
||||
|
||||
public:
|
||||
AWS_SCRIPT_BEHAVIOR_DEFINITION(AWSScriptBehaviorS3, "{7F4E956C-7463-4236-B320-C992D36A9C6E}");
|
||||
AZ_RTTI(AWSScriptBehaviorS3, "{7F4E956C-7463-4236-B320-C992D36A9C6E}");
|
||||
|
||||
AWSScriptBehaviorS3() = default;
|
||||
virtual ~AWSScriptBehaviorS3() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static void GetObject(const AZStd::string& bucketResourceKey, const AZStd::string& objectKey, const AZStd::string& outFile);
|
||||
static void GetObjectRaw(const AZStd::string& bucket, const AZStd::string& objectKey, const AZStd::string& region, const AZStd::string& outFile);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
@@ -30,23 +29,8 @@ namespace AWSCore
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
static bool AddedBehaviours()
|
||||
{
|
||||
return m_alreadyAddedBehaviors;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void AddBehaviors(); // Add any behaviors you derived from AWSScriptBehaviorBase to the implementation of this function
|
||||
|
||||
static AZStd::vector<AZStd::unique_ptr<AWSScriptBehaviorBase>> m_behaviors;
|
||||
static bool m_alreadyAddedBehaviors;
|
||||
};
|
||||
} // namespace AWSCore
|
||||
|
||||
@@ -20,39 +20,30 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AWSScriptBehaviorDynamoDB::AWSScriptBehaviorDynamoDB()
|
||||
void AWSScriptBehaviorDynamoDB::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::ReflectSerialization(AZ::SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AWSScriptBehaviorDynamoDB>()
|
||||
->Version(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::ReflectBehaviors(AZ::BehaviorContext* behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorDynamoDB>("AWSScriptBehaviorDynamoDB")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetItem", &AWSScriptBehaviorDynamoDB::GetItem,
|
||||
{{{"Table Resource KeyName", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."}}})
|
||||
->Method("GetItemRaw", &AWSScriptBehaviorDynamoDB::GetItemRaw,
|
||||
{{{"Table Name", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."},
|
||||
{"Region Name", "The region of the table located in."}}});
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorDynamoDB>("AWSScriptBehaviorDynamoDB")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetItem", &AWSScriptBehaviorDynamoDB::GetItem,
|
||||
{{{"Table Resource KeyName", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."}}})
|
||||
->Method("GetItemRaw", &AWSScriptBehaviorDynamoDB::GetItemRaw,
|
||||
{{{"Table Name", "The name of the table containing the requested item."},
|
||||
{"Key Map", "A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve."},
|
||||
{"Region Name", "The region of the table located in."}}});
|
||||
|
||||
behaviorContext->EBus<AWSScriptBehaviorDynamoDBNotificationBus>("AWSDynamoDBBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorDynamoDBNotificationBusHandler>();
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::ReflectEditParameters(AZ::EditContext* editContext)
|
||||
{
|
||||
AZ_UNUSED(editContext);
|
||||
behaviorContext->EBus<AWSScriptBehaviorDynamoDBNotificationBus>("AWSDynamoDBBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorDynamoDBNotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorDynamoDB::GetItem(const AZStd::string& tableResourceKey, const DynamoDBAttributeValueMap& keyMap)
|
||||
|
||||
@@ -21,39 +21,30 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AWSScriptBehaviorLambda::AWSScriptBehaviorLambda()
|
||||
void AWSScriptBehaviorLambda::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::ReflectSerialization(AZ::SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AWSScriptBehaviorLambda>()
|
||||
->Version(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::ReflectBehaviors(AZ::BehaviorContext* behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorLambda>("AWSScriptBehaviorLambda")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("Invoke", &AWSScriptBehaviorLambda::Invoke,
|
||||
{{{"Function Resource KeyName", "The resource key name of the lambda function in resource mapping config file."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."}}})
|
||||
->Method("InvokeRaw", &AWSScriptBehaviorLambda::InvokeRaw,
|
||||
{{{"Function Name", "The name of the Lambda function, version, or alias."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."},
|
||||
{"Region Name", "The region of the lambda function located in."}}});
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorLambda>("AWSScriptBehaviorLambda")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("Invoke", &AWSScriptBehaviorLambda::Invoke,
|
||||
{{{"Function Resource KeyName", "The resource key name of the lambda function in resource mapping config file."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."}}})
|
||||
->Method("InvokeRaw", &AWSScriptBehaviorLambda::InvokeRaw,
|
||||
{{{"Function Name", "The name of the Lambda function, version, or alias."},
|
||||
{"Payload", "The JSON that you want to provide to your Lambda function as input."},
|
||||
{"Region Name", "The region of the lambda function located in."}}});
|
||||
|
||||
behaviorContext->EBus<AWSScriptBehaviorLambdaNotificationBus>("AWSLambdaBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorLambdaNotificationBusHandler>();
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::ReflectEditParameters(AZ::EditContext* editContext)
|
||||
{
|
||||
AZ_UNUSED(editContext);
|
||||
behaviorContext->EBus<AWSScriptBehaviorLambdaNotificationBus>("AWSLambdaBehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorLambdaNotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorLambda::Invoke(const AZStd::string& functionResourceKey, const AZStd::string& payload)
|
||||
|
||||
@@ -24,49 +24,39 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AWSScriptBehaviorS3::AWSScriptBehaviorS3()
|
||||
void AWSScriptBehaviorS3::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::ReflectSerialization(AZ::SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AWSScriptBehaviorS3>()
|
||||
->Version(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::ReflectBehaviors(AZ::BehaviorContext* behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorS3>(AWSScriptBehaviorS3Name)
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetObject", &AWSScriptBehaviorS3::GetObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("GetObjectRaw", &AWSScriptBehaviorS3::GetObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("HeadObject", &AWSScriptBehaviorS3::HeadObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."}}})
|
||||
->Method("HeadObjectRaw", &AWSScriptBehaviorS3::HeadObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."}}})
|
||||
;
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<AWSScriptBehaviorS3>(AWSScriptBehaviorS3Name)
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Method("GetObject", &AWSScriptBehaviorS3::GetObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("GetObjectRaw", &AWSScriptBehaviorS3::GetObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."},
|
||||
{"Outfile Name", "Filename where the content will be saved."}}})
|
||||
->Method("HeadObject", &AWSScriptBehaviorS3::HeadObject,
|
||||
{{{"Bucket Resource KeyName", "The resource key name of the bucket in resource mapping config file."},
|
||||
{"Object KeyName", "The object key."}}})
|
||||
->Method("HeadObjectRaw", &AWSScriptBehaviorS3::HeadObjectRaw,
|
||||
{{{"Bucket Name", "The name of the bucket containing the object."},
|
||||
{"Object KeyName", "The object key."},
|
||||
{"Region Name", "The region of the bucket located in."}}});
|
||||
|
||||
behaviorContext->EBus<AWSScriptBehaviorS3NotificationBus>("AWSS3BehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorS3NotificationBusHandler>();
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::ReflectEditParameters(AZ::EditContext* editContext)
|
||||
{
|
||||
AZ_UNUSED(editContext);
|
||||
behaviorContext->EBus<AWSScriptBehaviorS3NotificationBus>("AWSS3BehaviorNotificationBus")
|
||||
->Attribute(AZ::Script::Attributes::Category, "AWSCore")
|
||||
->Handler<AWSScriptBehaviorS3NotificationBusHandler>();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorS3::GetObject(
|
||||
|
||||
@@ -12,35 +12,17 @@
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AZStd::vector<AZStd::unique_ptr<AWSScriptBehaviorBase>> AWSScriptBehaviorsComponent::m_behaviors;
|
||||
bool AWSScriptBehaviorsComponent::m_alreadyAddedBehaviors = false;
|
||||
|
||||
void AWSScriptBehaviorsComponent::AddBehaviors()
|
||||
{
|
||||
if (!m_alreadyAddedBehaviors)
|
||||
{
|
||||
// Add new script behaviors here
|
||||
m_behaviors.push_back(AZStd::make_unique<AWSScriptBehaviorDynamoDB>());
|
||||
m_behaviors.push_back(AZStd::make_unique<AWSScriptBehaviorLambda>());
|
||||
m_behaviors.push_back(AZStd::make_unique<AWSScriptBehaviorS3>());
|
||||
m_alreadyAddedBehaviors = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AddBehaviors();
|
||||
AWSScriptBehaviorDynamoDB::Reflect(context);
|
||||
AWSScriptBehaviorLambda::Reflect(context);
|
||||
AWSScriptBehaviorS3::Reflect(context);
|
||||
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<AWSScriptBehaviorsComponent, AZ::Component>()
|
||||
->Version(0);
|
||||
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->ReflectSerialization(serialize);
|
||||
}
|
||||
|
||||
if (AZ::EditContext* editContext = serialize->GetEditContext())
|
||||
{
|
||||
editContext->Class<AWSScriptBehaviorsComponent>("AWSScriptBehaviors", "Provides ScriptCanvas functions for calling AWS")
|
||||
@@ -49,19 +31,6 @@ namespace AWSCore
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("AWS"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->ReflectEditParameters(editContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->ReflectBehaviors(behaviorContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,31 +55,12 @@ namespace AWSCore
|
||||
AZ_UNUSED(dependent);
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Init()
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->Init();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Activate()
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
void AWSScriptBehaviorsComponent::Deactivate()
|
||||
{
|
||||
for (auto&& behavior : m_behaviors)
|
||||
{
|
||||
behavior->Deactivate();
|
||||
}
|
||||
|
||||
// this forces the vector to release its capacity, clear/shrink_to_fit is not
|
||||
m_behaviors.swap(AZStd::vector<AZStd::unique_ptr<AWSScriptBehaviorBase>>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,18 +15,6 @@
|
||||
|
||||
using namespace AWSCore;
|
||||
|
||||
class AWSScriptBehaviorsComponentMock
|
||||
: public AWSScriptBehaviorsComponent
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AWSScriptBehaviorsComponentMock, "{78579706-E1B2-4788-A34D-A58D3F273FF9}");
|
||||
|
||||
int GetBehaviorsNum()
|
||||
{
|
||||
return m_behaviors.size();
|
||||
}
|
||||
};
|
||||
|
||||
class AWSScriptBehaviorsComponentTest
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
@@ -38,7 +26,7 @@ public:
|
||||
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
|
||||
|
||||
m_entity = AZStd::make_unique<AZ::Entity>();
|
||||
m_scriptBehaviorsComponent.reset(m_entity->CreateComponent<AWSScriptBehaviorsComponentMock>());
|
||||
m_scriptBehaviorsComponent.reset(m_entity->CreateComponent<AWSScriptBehaviorsComponent>());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@@ -56,20 +44,16 @@ protected:
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_componentDescriptor;
|
||||
AZStd::unique_ptr<AWSScriptBehaviorsComponentMock> m_scriptBehaviorsComponent;
|
||||
AZStd::unique_ptr<AWSScriptBehaviorsComponent> m_scriptBehaviorsComponent;
|
||||
AZStd::unique_ptr<AZ::Entity> m_entity;
|
||||
};
|
||||
|
||||
TEST_F(AWSScriptBehaviorsComponentTest, InitActivateDeactivate_Call_GetExpectedNumOfAddedBehaviors)
|
||||
TEST_F(AWSScriptBehaviorsComponentTest, Reflect)
|
||||
{
|
||||
m_componentDescriptor.reset(AWSScriptBehaviorsComponentMock::CreateDescriptor());
|
||||
int oldEBusNum = m_behaviorContext->m_ebuses.size();
|
||||
m_componentDescriptor.reset(AWSScriptBehaviorsComponent::CreateDescriptor());
|
||||
m_componentDescriptor->Reflect(m_serializeContext.get());
|
||||
m_componentDescriptor->Reflect(m_behaviorContext.get());
|
||||
EXPECT_TRUE(AWSScriptBehaviorsComponentMock::AddedBehaviours());
|
||||
EXPECT_TRUE(m_scriptBehaviorsComponent->GetBehaviorsNum() == 3);
|
||||
|
||||
m_entity->Init();
|
||||
m_entity->Activate();
|
||||
m_entity->Deactivate();
|
||||
EXPECT_TRUE(m_scriptBehaviorsComponent->GetBehaviorsNum() == 0);
|
||||
EXPECT_TRUE(m_behaviorContext->m_ebuses.size() - oldEBusNum == 3);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ set(FILES
|
||||
Include/Public/Framework/ServiceRequestJobConfig.h
|
||||
Include/Public/Framework/Util.h
|
||||
Include/Public/ResourceMapping/AWSResourceMappingBus.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorBase.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorDynamoDB.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorLambda.h
|
||||
Include/Public/ScriptCanvas/AWSScriptBehaviorS3.h
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace AZ
|
||||
shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder";
|
||||
// Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update
|
||||
// ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder".
|
||||
shaderVariantAssetBuilderDescriptor.m_version = 23; // ATOM-15472
|
||||
shaderVariantAssetBuilderDescriptor.m_version = 24; // ATOM-15978
|
||||
shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
|
||||
shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid<ShaderVariantAssetBuilder>();
|
||||
shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#include "ShaderAssetBuilder.h"
|
||||
#include "ShaderBuilderUtility.h"
|
||||
#include "SrgLayoutUtility.h"
|
||||
#include "AzslData.h"
|
||||
#include "AzslCompiler.h"
|
||||
#include <CommonFiles/Preprocessor.h>
|
||||
@@ -520,6 +521,96 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool LoadSrgLayoutListFromShaderAssetBuilder(
|
||||
const RHI::ShaderPlatformInterface* shaderPlatformInterface,
|
||||
const AssetBuilderSDK::PlatformInfo& platformInfo,
|
||||
const AzslCompiler& azslCompiler, const AZStd::string& shaderSourceFileFullPath,
|
||||
const RPI::SupervariantIndex supervariantIndex,
|
||||
const bool platformUsesRegisterSpaces,
|
||||
RPI::ShaderResourceGroupLayoutList& srgLayoutList,
|
||||
RootConstantData& rootConstantData)
|
||||
{
|
||||
auto srgJsonPathOutcome = ShaderBuilderUtility::ObtainBuildArtifactPathFromShaderAssetBuilder(
|
||||
shaderPlatformInterface->GetAPIUniqueIndex(), platformInfo.m_identifier, shaderSourceFileFullPath, supervariantIndex.GetIndex(), AZ::RPI::ShaderAssetSubId::SrgJson);
|
||||
if (!srgJsonPathOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", srgJsonPathOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto srgJsonPath = srgJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
SrgDataContainer srgData;
|
||||
if (!azslCompiler.ParseSrgPopulateSrgData(jsonOutcome.GetValue(), srgData))
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse srg data");
|
||||
return false;
|
||||
}
|
||||
// Add all Shader Resource Group Assets that were defined in the shader code to the shader asset
|
||||
if (!SrgLayoutUtility::LoadShaderResourceGroupLayouts(ShaderVariantAssetBuilderName, srgData, platformUsesRegisterSpaces, srgLayoutList))
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to load ShaderResourceGroupLayouts");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto srgLayout : srgLayoutList)
|
||||
{
|
||||
if (!srgLayout->Finalize())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false,
|
||||
"Failed to finalize SrgLayout %s", srgLayout->GetName().GetCStr());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Access the root constants reflection
|
||||
if (!azslCompiler.ParseSrgPopulateRootConstantData(
|
||||
jsonOutcome.GetValue(),
|
||||
rootConstantData)) // consuming data from --srg ("InlineConstantBuffer" subjson section)
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to obtain root constant data reflection");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadBindingDependenciesFromShaderAssetBuilder(
|
||||
const RHI::ShaderPlatformInterface* shaderPlatformInterface,
|
||||
const AssetBuilderSDK::PlatformInfo& platformInfo,
|
||||
const AzslCompiler& azslCompiler, const AZStd::string& shaderSourceFileFullPath,
|
||||
const RPI::SupervariantIndex supervariantIndex,
|
||||
BindingDependencies& bindingDependencies)
|
||||
{
|
||||
auto bindingsJsonPathOutcome = ShaderBuilderUtility::ObtainBuildArtifactPathFromShaderAssetBuilder(
|
||||
shaderPlatformInterface->GetAPIUniqueIndex(), platformInfo.m_identifier, shaderSourceFileFullPath, supervariantIndex.GetIndex(), AZ::RPI::ShaderAssetSubId::BindingdepJson);
|
||||
if (!bindingsJsonPathOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", bindingsJsonPathOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bindingsJsonPath = bindingsJsonPathOutcome.TakeValue();
|
||||
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath);
|
||||
if (!jsonOutcome.IsSuccess())
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
|
||||
return false;
|
||||
}
|
||||
if (!azslCompiler.ParseBindingdepPopulateBindingDependencies(jsonOutcome.GetValue(), bindingDependencies))
|
||||
{
|
||||
AZ_Error(ShaderVariantAssetBuilderName, false, "Failed to parse binding dependencies data");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Returns the content of the hlsl file for the given supervariant as produced by ShaderAsssetBuilder.
|
||||
@@ -773,6 +864,50 @@ namespace AZ
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
//! It is important to keep this refcounted pointer outside of the if block to prevent it from being destroyed.
|
||||
RHI::Ptr<RHI::PipelineLayoutDescriptor> pipelineLayoutDescriptor;
|
||||
if (shaderPlatformInterface->VariantCompilationRequiresSrgLayoutData())
|
||||
{
|
||||
AZStd::string azslcCompilerParameters =
|
||||
shaderPlatformInterface->GetAzslCompilerParameters(buildOptions.m_compilerArguments);
|
||||
const bool platformUsesRegisterSpaces =
|
||||
(AzFramework::StringFunc::Find(azslcCompilerParameters, "--use-spaces") != AZStd::string::npos);
|
||||
|
||||
RPI::ShaderResourceGroupLayoutList srgLayoutList;
|
||||
RootConstantData rootConstantData;
|
||||
if (!LoadSrgLayoutListFromShaderAssetBuilder(
|
||||
shaderPlatformInterface, request.m_platformInfo, azslc, shaderSourceFileFullPath, supervariantIndex,
|
||||
platformUsesRegisterSpaces,
|
||||
srgLayoutList,
|
||||
rootConstantData))
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
BindingDependencies bindingDependencies;
|
||||
if (!LoadBindingDependenciesFromShaderAssetBuilder(
|
||||
shaderPlatformInterface, request.m_platformInfo, azslc, shaderSourceFileFullPath, supervariantIndex,
|
||||
bindingDependencies))
|
||||
{
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
pipelineLayoutDescriptor =
|
||||
ShaderBuilderUtility::BuildPipelineLayoutDescriptorForApi(
|
||||
ShaderVariantAssetBuilderName, srgLayoutList, shaderEntryPoints, buildOptions.m_compilerArguments, rootConstantData,
|
||||
shaderPlatformInterface, bindingDependencies);
|
||||
if (!pipelineLayoutDescriptor)
|
||||
{
|
||||
AZ_Error(
|
||||
ShaderVariantAssetBuilderName, false, "Failed to build pipeline layout descriptor for api=[%s]",
|
||||
shaderPlatformInterface->GetAPIName().GetCStr());
|
||||
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the shader variant creation context:
|
||||
ShaderVariantCreationContext shaderVariantCreationContext =
|
||||
|
||||
@@ -144,6 +144,12 @@ namespace AZ
|
||||
const ShaderResourceGroupInfoList& srgInfoList,
|
||||
const RootConstantsInfo& rootConstantsInfo,
|
||||
const ShaderCompilerArguments& shaderCompilerArguments) = 0;
|
||||
|
||||
//! In general, shader compilation doesn't require SRG Layout data, but RHIs like
|
||||
//! Metal don't do well if unused resources (descriptors) are not bound. If this function returns TRUE
|
||||
//! the ShaderVariantAssetBuilder will invoke BuildPipelineLayoutDescriptor() so the RHI gets the chance to
|
||||
//! build SRG Layout data which will be useful when compiling MetalISL to Metal byte code.
|
||||
virtual bool VariantCompilationRequiresSrgLayoutData() const { return false; }
|
||||
|
||||
//! See AZ::RHI::Factory::GetAPIUniqueIndex() for details.
|
||||
//! See AZ::RHI::Limits::APIType::PerPlatformApiUniqueIndexMax.
|
||||
|
||||
@@ -159,7 +159,13 @@ namespace AZ
|
||||
arguments += " -Zi"; // Generate debug information
|
||||
arguments += " -Zss"; // Compute Shader Hash considering source information
|
||||
}
|
||||
arguments += " " + m_dxcAdditionalFreeArguments;
|
||||
// strip spaces at both sides
|
||||
AZStd::string dxcAdditionalFreeArguments = m_dxcAdditionalFreeArguments;
|
||||
AzFramework::StringFunc::TrimWhiteSpace(dxcAdditionalFreeArguments, true, true);
|
||||
if (!dxcAdditionalFreeArguments.empty())
|
||||
{
|
||||
arguments += " " + dxcAdditionalFreeArguments;
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace AZ
|
||||
const ShaderResourceGroupInfoList& srgInfoList,
|
||||
const RootConstantsInfo& rootConstantsInfo,
|
||||
const RHI::ShaderCompilerArguments& shaderCompilerArguments) override;
|
||||
|
||||
bool VariantCompilationRequiresSrgLayoutData() const override { return true; }
|
||||
|
||||
bool CompilePlatformInternal(
|
||||
const AssetBuilderSDK::PlatformInfo& platform,
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace AZ
|
||||
{
|
||||
AZ_UNUSED(device);
|
||||
m_hardwareQueueClass = hardwareQueueClass;
|
||||
m_supportsInterDrawTimestamps = AZ::RHI::QueryTypeFlags::Timestamp == (device->GetFeatures().m_queryTypesMask[static_cast<uint32_t>(hardwareQueueClass)] & AZ::RHI::QueryTypeFlags::Timestamp);
|
||||
}
|
||||
|
||||
void CommandListBase::Reset()
|
||||
@@ -64,7 +65,10 @@ namespace AZ
|
||||
[m_encoder endEncoding];
|
||||
m_encoder = nil;
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
m_timeStampQueue.clear();
|
||||
if (m_supportsInterDrawTimestamps)
|
||||
{
|
||||
m_timeStampQueue.clear();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -144,9 +148,12 @@ namespace AZ
|
||||
m_isEncoded = true;
|
||||
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
for(auto& timeStamp: m_timeStampQueue)
|
||||
if (m_supportsInterDrawTimestamps)
|
||||
{
|
||||
SampleCounters(timeStamp.m_counterSampleBuffer, timeStamp.m_timeStampIndex);
|
||||
for(auto& timeStamp: m_timeStampQueue)
|
||||
{
|
||||
SampleCounters(timeStamp.m_counterSampleBuffer, timeStamp.m_timeStampIndex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -195,6 +202,11 @@ namespace AZ
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
void CommandListBase::SampleCounters(id<MTLCounterSampleBuffer> counterSampleBuffer, uint32_t sampleIndex)
|
||||
{
|
||||
if (!m_supportsInterDrawTimestamps)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ_Assert(sampleIndex >= 0, "Invalid sample index");
|
||||
//useBarrier - Inserting a barrier ensures that encoded work is complete before the GPU samples the hardware counters.
|
||||
//If it is true there is a performance penalty but you will get consistent results
|
||||
@@ -231,6 +243,11 @@ namespace AZ
|
||||
|
||||
void CommandListBase::SamplePassCounters(id<MTLCounterSampleBuffer> counterSampleBuffer, uint32_t sampleIndex)
|
||||
{
|
||||
if (!m_supportsInterDrawTimestamps)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_encoder == nil)
|
||||
{
|
||||
//Queue the query to be activated upon encoder creation. Applies to timestamp queries
|
||||
|
||||
@@ -101,6 +101,8 @@ namespace AZ
|
||||
|
||||
const AZStd::set<id<MTLHeap>>* m_residentHeaps = nullptr;
|
||||
|
||||
bool m_supportsInterDrawTimestamps = AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING; // iOS/TVOS = false, MacOS = defaults to true
|
||||
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
struct TimeStampData
|
||||
{
|
||||
|
||||
@@ -328,14 +328,28 @@ namespace AZ
|
||||
m_features.m_indirectDrawSupport = false;
|
||||
|
||||
RHI::QueryTypeFlags counterSamplingFlags = RHI::QueryTypeFlags::None;
|
||||
|
||||
#if AZ_TRAIT_ATOM_METAL_COUNTER_SAMPLING
|
||||
counterSamplingFlags |= (RHI::QueryTypeFlags::Timestamp | RHI::QueryTypeFlags::PipelineStatistics);
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Copy)] = RHI::QueryTypeFlags::Timestamp;
|
||||
|
||||
bool supportsInterDrawTimestamps = true;
|
||||
#if defined(__IPHONE_14_0) || defined(__MAC_11_0) || defined(__TVOS_14_0)
|
||||
if (@available(macOS 11.0, iOS 14, tvOS 14, *))
|
||||
{
|
||||
supportsInterDrawTimestamps = [m_metalDevice supportsCounterSampling:MTLCounterSamplingPointAtDrawBoundary];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
supportsInterDrawTimestamps = ![m_metalDevice.name containsString:@"Apple"]; // Apple GPU's don't support inter draw timestamps at the M1/A14 generation
|
||||
}
|
||||
|
||||
if (supportsInterDrawTimestamps)
|
||||
{
|
||||
counterSamplingFlags |= (RHI::QueryTypeFlags::Timestamp | RHI::QueryTypeFlags::PipelineStatistics);
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Copy)] = RHI::QueryTypeFlags::Timestamp;
|
||||
}
|
||||
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Graphics)] = RHI::QueryTypeFlags::Occlusion | counterSamplingFlags;
|
||||
//Compute queue can do gfx work
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Compute)] = RHI::QueryTypeFlags::Occlusion |counterSamplingFlags;
|
||||
m_features.m_queryTypesMask[static_cast<uint32_t>(RHI::HardwareQueueClass::Compute)] = RHI::QueryTypeFlags::Occlusion | counterSamplingFlags;
|
||||
m_features.m_occlusionQueryPrecise = true;
|
||||
|
||||
//Values taken from https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
||||
|
||||
@@ -218,7 +218,8 @@ namespace AZ
|
||||
createInfo.extent = extent;
|
||||
createInfo.mipLevels = AZStd::min<uint32_t>(descriptor.m_mipLevels, formatProps.maxMipLevels);
|
||||
createInfo.arrayLayers = AZStd::min<uint32_t>(descriptor.m_arraySize, formatProps.maxArrayLayers);
|
||||
createInfo.samples = static_cast<VkSampleCountFlagBits>(RHI::FilterBits(static_cast<VkSampleCountFlags>(ConvertSampleCount(descriptor.m_multisampleState.m_samples)), formatProps.sampleCounts));
|
||||
VkSampleCountFlagBits sampleCountFlagBits = static_cast<VkSampleCountFlagBits>(RHI::FilterBits(static_cast<VkSampleCountFlags>(ConvertSampleCount(descriptor.m_multisampleState.m_samples)), formatProps.sampleCounts));
|
||||
createInfo.samples = (static_cast<uint32_t>(sampleCountFlagBits) > 0) ? sampleCountFlagBits : VK_SAMPLE_COUNT_1_BIT;
|
||||
createInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
createInfo.usage = GetImageUsageFlags();
|
||||
createInfo.sharingMode = exclusiveOwnership ? VK_SHARING_MODE_EXCLUSIVE : VK_SHARING_MODE_CONCURRENT;
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace AZ
|
||||
{
|
||||
AZ_Assert(IsQueryTypeValid(queryType), "Provided QueryType is invalid");
|
||||
|
||||
return static_cast<uint32_t>(m_queryTypeSupport) & static_cast<uint32_t>(queryType);
|
||||
return static_cast<uint32_t>(m_queryTypeSupport) & AZ_BIT(static_cast<uint32_t>(queryType));
|
||||
}
|
||||
|
||||
RPI::QueryPool* GpuQuerySystem::GetQueryPoolByType(RHI::QueryType queryType)
|
||||
|
||||
@@ -237,8 +237,8 @@ namespace EditorPythonBindings
|
||||
{
|
||||
ec->Class<PythonSystemComponent>("PythonSystemComponent", "The Python interpreter")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -284,10 +284,10 @@ namespace EditorPythonBindings
|
||||
ReleaseFunction m_releaseFunction;
|
||||
};
|
||||
ReleaseInitalizeWaiterScope scope([this]()
|
||||
{
|
||||
m_initalizeWaiter.release(m_initalizeWaiterCount);
|
||||
m_initalizeWaiterCount = 0;
|
||||
});
|
||||
{
|
||||
m_initalizeWaiter.release(m_initalizeWaiterCount);
|
||||
m_initalizeWaiterCount = 0;
|
||||
});
|
||||
|
||||
if (Py_IsInitialized())
|
||||
{
|
||||
@@ -327,6 +327,11 @@ namespace EditorPythonBindings
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PythonSystemComponent::IsPythonActive()
|
||||
{
|
||||
return Py_IsInitialized() != 0;
|
||||
}
|
||||
|
||||
void PythonSystemComponent::WaitForInitialization()
|
||||
{
|
||||
m_initalizeWaiterCount++;
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace EditorPythonBindings
|
||||
// AzToolsFramework::EditorPythonEventsInterface
|
||||
bool StartPython(bool silenceWarnings = false) override;
|
||||
bool StopPython(bool silenceWarnings = false) override;
|
||||
bool IsPythonActive() override;
|
||||
void WaitForInitialization() override;
|
||||
void ExecuteWithLock(AZStd::function<void()> executionCallback) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -209,12 +209,17 @@ namespace Gestures
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline uint32_t IRecognizer::GetGesturePointerIndex(const AzFramework::InputChannel& inputChannel)
|
||||
{
|
||||
const auto& mouseButtonIt = AZStd::find(AzFramework::InputDeviceMouse::Button::All.cbegin(),
|
||||
AzFramework::InputDeviceMouse::Button::All.cend(),
|
||||
inputChannel.GetInputChannelId());
|
||||
if (mouseButtonIt != AzFramework::InputDeviceMouse::Button::All.cend())
|
||||
// Only recognize gestures for the default mouse input device. The Editor may register synthetic
|
||||
// mouse input devices with the same mouse input channels, which can confuse gesture recognition.
|
||||
if (inputChannel.GetInputDevice().GetInputDeviceId() == AzFramework::InputDeviceMouse::Id)
|
||||
{
|
||||
return static_cast<uint32_t>(mouseButtonIt - AzFramework::InputDeviceMouse::Button::All.cbegin());
|
||||
const auto& mouseButtonIt = AZStd::find(AzFramework::InputDeviceMouse::Button::All.cbegin(),
|
||||
AzFramework::InputDeviceMouse::Button::All.cend(),
|
||||
inputChannel.GetInputChannelId());
|
||||
if (mouseButtonIt != AzFramework::InputDeviceMouse::Button::All.cend())
|
||||
{
|
||||
return static_cast<uint32_t>(mouseButtonIt - AzFramework::InputDeviceMouse::Button::All.cbegin());
|
||||
}
|
||||
}
|
||||
|
||||
const auto& touchIndexIt = AZStd::find(AzFramework::InputDeviceTouch::Touch::All.cbegin(),
|
||||
|
||||
@@ -63,7 +63,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
AUTORCC
|
||||
FILES_CMAKE
|
||||
lyshine_uicanvaseditor_files.cmake
|
||||
lyshine_editor_builder_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
@@ -78,7 +77,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
3rdParty::Qt::Widgets
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AssetBuilderSDK
|
||||
Legacy::EditorCommon
|
||||
Legacy::EditorCore
|
||||
Gem::LyShine.Static
|
||||
@@ -98,7 +96,6 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
|
||||
ly_add_target(
|
||||
NAME LyShine.Editor GEM_MODULE
|
||||
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
lyshine_common_module_files.cmake
|
||||
@@ -115,17 +112,72 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
AZ::AssetBuilderSDK
|
||||
AZ::AzToolsFramework
|
||||
Gem::LyShine.Editor.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
RUNTIME_DEPENDENCIES
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
)
|
||||
)
|
||||
|
||||
# by naming this target LyShine.Builders it ensures that it is loaded
|
||||
# in any pipeline tools (Like Asset Processor, AssetBuilder, etc)
|
||||
ly_add_target(
|
||||
NAME LyShine.Builders.Static STATIC
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
lyshine_editor_builder_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
Source
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzCore
|
||||
AZ::AzToolsFramework
|
||||
AZ::AssetBuilderSDK
|
||||
Gem::LyShine.Static
|
||||
Legacy::CryCommon
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
Gem::AtomToolsFramework.Static
|
||||
Gem::AtomToolsFramework.Editor
|
||||
${additional_dependencies}
|
||||
PUBLIC
|
||||
Gem::Atom_RPI.Public
|
||||
Gem::Atom_Utils.Static
|
||||
Gem::Atom_Bootstrap.Headers
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME LyShine.Builders GEM_MODULE
|
||||
NAMESPACE Gem
|
||||
OUTPUT_NAME Gem.LyShine.Builders
|
||||
FILES_CMAKE
|
||||
lyshine_common_module_files.cmake
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
LYSHINE_BUILDER
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
Source
|
||||
Editor
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
AZ::AssetBuilderSDK
|
||||
Gem::LyShine.Builders.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas.Editor
|
||||
)
|
||||
|
||||
# by default, load the above "Gem::LyShine.Editor" module in dev tools:
|
||||
ly_create_alias(NAME LyShine.Builders NAMESPACE Gem TARGETS Gem::LyShine.Editor)
|
||||
ly_create_alias(NAME LyShine.Tools NAMESPACE Gem TARGETS Gem::LyShine.Editor)
|
||||
endif()
|
||||
|
||||
@@ -169,6 +221,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
LYSHINE_EDITOR
|
||||
LYSHINE_BUILDER
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Tests
|
||||
@@ -182,6 +235,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
Legacy::CryCommon
|
||||
AZ::AssetBuilderSDK
|
||||
Gem::LyShine.Editor.Static
|
||||
Gem::LyShine.Builders.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
Gem::TextureAtlas
|
||||
RUNTIME_DEPENDENCIES
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
#include "World/UiCanvasProxyRefComponent.h"
|
||||
#include "World/UiCanvasOnMeshComponent.h"
|
||||
|
||||
#if defined (LYSHINE_EDITOR)
|
||||
# include "Pipeline/LyShineBuilder/LyShineBuilderComponent.h"
|
||||
#endif // LYSHINE_EDITOR
|
||||
#if defined(LYSHINE_BUILDER)
|
||||
#include "Pipeline/LyShineBuilder/LyShineBuilderComponent.h"
|
||||
#endif // LYSHINE_BUILDER
|
||||
|
||||
namespace LyShine
|
||||
{
|
||||
@@ -64,7 +64,7 @@ namespace LyShine
|
||||
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
LyShineSystemComponent::CreateDescriptor(),
|
||||
#if defined (LYSHINE_EDITOR)
|
||||
#if defined(LYSHINE_EDITOR)
|
||||
LyShineEditor::LyShineEditorSystemComponent::CreateDescriptor(),
|
||||
#endif
|
||||
UiCanvasAssetRefComponent::CreateDescriptor(),
|
||||
@@ -103,7 +103,7 @@ namespace LyShine
|
||||
UiRadioButtonComponent::CreateDescriptor(),
|
||||
UiRadioButtonGroupComponent::CreateDescriptor(),
|
||||
UiParticleEmitterComponent::CreateDescriptor(),
|
||||
#if defined(LYSHINE_EDITOR)
|
||||
#if defined(LYSHINE_BUILDER)
|
||||
// Builder
|
||||
LyShineBuilder::LyShineBuilderComponent::CreateDescriptor(),
|
||||
#endif
|
||||
@@ -123,7 +123,7 @@ namespace LyShine
|
||||
{
|
||||
return AZ::ComponentTypeList{
|
||||
azrtti_typeid<LyShineSystemComponent>(),
|
||||
#if defined (LYSHINE_EDITOR)
|
||||
#if defined(LYSHINE_EDITOR)
|
||||
azrtti_typeid<LyShineEditor::LyShineEditorSystemComponent>(),
|
||||
#endif
|
||||
#if AZ_LOADSCREENCOMPONENT_ENABLED
|
||||
|
||||
@@ -148,7 +148,6 @@ namespace LyShine
|
||||
{
|
||||
LyShineAllocatorScope::ActivateAllocators();
|
||||
|
||||
LyShineRequestBus::Handler::BusConnect();
|
||||
UiSystemBus::Handler::BusConnect();
|
||||
UiSystemToolsBus::Handler::BusConnect();
|
||||
UiFrameworkBus::Handler::BusConnect();
|
||||
@@ -196,7 +195,6 @@ namespace LyShine
|
||||
UiSystemBus::Handler::BusDisconnect();
|
||||
UiSystemToolsBus::Handler::BusDisconnect();
|
||||
UiFrameworkBus::Handler::BusDisconnect();
|
||||
LyShineRequestBus::Handler::BusDisconnect();
|
||||
CrySystemEventBus::Handler::BusDisconnect();
|
||||
|
||||
LyShineAllocatorScope::DeactivateAllocators();
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <LmbrCentral/Rendering/MaterialAsset.h>
|
||||
|
||||
#include <LyShine/LyShineBus.h>
|
||||
#include <LyShine/Bus/UiSystemBus.h>
|
||||
#include <LyShine/Bus/UiCanvasManagerBus.h>
|
||||
#include <LyShine/Bus/Tools/UiSystemToolsBus.h>
|
||||
@@ -28,7 +27,6 @@ namespace LyShine
|
||||
|
||||
class LyShineSystemComponent
|
||||
: public AZ::Component
|
||||
, protected LyShineRequestBus::Handler
|
||||
, protected UiSystemBus::Handler
|
||||
, protected UiSystemToolsBus::Handler
|
||||
, protected LyShineAllocatorScope
|
||||
|
||||
@@ -8,4 +8,6 @@
|
||||
set(FILES
|
||||
Source/LyShineModule.cpp
|
||||
Source/LyShineModule.h
|
||||
Source/LyShineSystemComponent.cpp
|
||||
Source/LyShineSystemComponent.h
|
||||
)
|
||||
|
||||
@@ -26,8 +26,6 @@ set(FILES
|
||||
Source/EditorPropertyTypes.h
|
||||
Source/LyShineLoadScreen.cpp
|
||||
Source/LyShineLoadScreen.h
|
||||
Source/LyShineSystemComponent.cpp
|
||||
Source/LyShineSystemComponent.h
|
||||
Source/RenderGraph.cpp
|
||||
Source/RenderGraph.h
|
||||
Source/TextMarkup.cpp
|
||||
|
||||
@@ -61,6 +61,7 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::SceneCore
|
||||
AZ::SceneData
|
||||
AZ::SceneUI
|
||||
)
|
||||
# the SceneProcessing.Editor module above is only used in Builders and Tools.
|
||||
ly_create_alias(NAME SceneProcessing.Builders NAMESPACE Gem TARGETS Gem::SceneProcessing.Editor)
|
||||
|
||||
@@ -52,18 +52,4 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT TestTools
|
||||
)
|
||||
|
||||
# Example tests.
|
||||
ly_add_pytest(
|
||||
NAME LyTestTools_ExampleTests_periodic_no_gpu
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/example/test_system_example.py
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
AssetProcessor
|
||||
AutomatedTesting.GameLauncher
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT TestTools
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
@@ -1,129 +0,0 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
Example test using LyTestTools to test Lumberyard.
|
||||
"""
|
||||
# Python built-in dependencies.
|
||||
import logging
|
||||
|
||||
# Third party dependencies.
|
||||
import pytest
|
||||
|
||||
# ly_test_tools dependencies.
|
||||
import ly_test_tools.log.log_monitor
|
||||
import ly_remote_console.remote_console_commands as remote_console_commands
|
||||
|
||||
# Configuring the logging is done in ly_test_tools at the following location:
|
||||
# ~/dev/Tools/LyTestTools/ly_test_tools/_internal/log/py_logging_util.py
|
||||
|
||||
# Use the following logging pattern to hook all test logging together:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def remote_console(request):
|
||||
"""
|
||||
Creates a RemoteConsole() class instance to send console commands to the
|
||||
Lumberyard client console.
|
||||
:param request: _pytest.fixtures.SubRequest class that handles getting
|
||||
a pytest fixture from a pytest function/fixture.
|
||||
:return: ly_remote_console.remote_console_commands.RemoteConsole class instance
|
||||
representing the Lumberyard remote console executable.
|
||||
"""
|
||||
# Initialize the RemoteConsole object to send commands to the Lumberyard client console.
|
||||
console = remote_console_commands.RemoteConsole()
|
||||
|
||||
# Custom teardown method for this remote_console fixture.
|
||||
def teardown():
|
||||
console.stop()
|
||||
|
||||
# Utilize request.addfinalizer() to add custom teardown() methods.
|
||||
request.addfinalizer(teardown) # This pattern must be used in pytest version
|
||||
|
||||
return console
|
||||
|
||||
# Shared parameters & fixtures for all test methods inside the TestSystemExample class.
|
||||
@pytest.mark.usefixtures("automatic_process_killer")
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
class TestSystemExample(object):
|
||||
"""
|
||||
Example test case class to hold a set of test case methods.
|
||||
|
||||
The amount of tests run is based on the parametrization stacking made in each test method or class.
|
||||
For this test, we placed unique test values in test methods and shared test values in the test class.
|
||||
We also assume building has already been done, but the test should error if the build is mis-configured.
|
||||
"""
|
||||
# This test method needs specific parameters not shared by all other tests in the class.
|
||||
# For targeting specific launchers, use the 'launcher_platform' pytest param like below:
|
||||
# @pytest.mark.parametrize("launcher_platform", ['android'])
|
||||
# If you want to target different AssetProcessor platforms, use asset_processor_platform:
|
||||
# @pytest.mark.parametrize("asset_processor_platform", ['android'])
|
||||
@pytest.mark.parametrize('level', ['simple_jacklocomotion'])
|
||||
@pytest.mark.parametrize('load_wait', [120])
|
||||
@pytest.mark.test_case_id('C16806863')
|
||||
def test_SystemTestExample_AllSupportedPlatforms_LaunchAutomatedTesting(
|
||||
# launcher_platform, asset_processor_platform, # Re-add these here if you plan to use them.
|
||||
self, launcher, remote_console, level, load_wait):
|
||||
"""
|
||||
Tests launching the AutomatedTesting then launches the Lumberyard client &
|
||||
loads the "simple_jacklocomotion" level using the remote console.
|
||||
Assumes the user already setup & built their machine for the test.
|
||||
"""
|
||||
# Launch the Lumberyard client & remote console test case:
|
||||
with launcher.start():
|
||||
remote_console.start()
|
||||
launcher_load = remote_console.expect_log_line(
|
||||
match_string='Level system is loading "simple_jacklocomotion"',
|
||||
timeout=load_wait)
|
||||
|
||||
# Assert loading was successful using remote console logs:
|
||||
assert launcher_load, (
|
||||
'Launcher failed to load Lumberyard client with the '
|
||||
f'"{level}" level - waited "{load_wait}" seconds.')
|
||||
|
||||
# This test method only needs pytest.mark report values and shared test class parameters.
|
||||
@pytest.mark.parametrize('processes_to_kill', ['Editor.exe'])
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.test_case_id('C16806864')
|
||||
def test_SystemTestExample_AllSupportedPlatforms_LaunchEditor(self, editor, processes_to_kill, launcher_platform):
|
||||
"""
|
||||
Tests launching the Lumberyard Editor is successful with the current build.
|
||||
"""
|
||||
# Launch the Lumberyard editor & verify load is successful:
|
||||
with editor.start():
|
||||
assert editor.is_alive(), (
|
||||
'Editor failed to launch for the current Lumberyard build.')
|
||||
|
||||
# Log monitoring example test.
|
||||
@pytest.mark.parametrize('level', ['simple_jacklocomotion'])
|
||||
@pytest.mark.parametrize('expected_lines', [['Log Monitoring test 1', 'Log Monitoring test 2']])
|
||||
@pytest.mark.parametrize('unexpected_lines', [['Unexpected test 1', 'Unexpected test 2']])
|
||||
@pytest.mark.test_case_id('C21202585')
|
||||
def test_SystemTestExample_AllSupportedPlatforms_LogMonitoring(self, level, launcher, expected_lines,
|
||||
unexpected_lines):
|
||||
"""
|
||||
Tests that the logging paths created by LyTestTools can be monitored for results using the log monitor.
|
||||
"""
|
||||
# Launch the Lumberyard client & initialize the log monitor.
|
||||
file_to_monitor = launcher.workspace.info_log_path
|
||||
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher,
|
||||
log_file_path=file_to_monitor)
|
||||
|
||||
# Generate log lines to the info log using logger.
|
||||
for expected_line in expected_lines:
|
||||
logger.info(expected_line)
|
||||
|
||||
# Start the Lumberyard client & test that the lines we logged can be viewed by the log monitor.
|
||||
with launcher.start():
|
||||
log_test = log_monitor.monitor_log_for_lines(
|
||||
expected_lines=expected_lines, # Defaults to None.
|
||||
unexpected_lines=unexpected_lines, # Defaults to None.
|
||||
halt_on_unexpected=True, # Defaults to False.
|
||||
timeout=60) # Defaults to 30
|
||||
|
||||
# Assert the log monitor detected expected lines and did not detect any unexpected lines.
|
||||
assert log_test, (
|
||||
f'Log monitoring failed. Used expected_lines values: {expected_lines} & '
|
||||
f'unexpected_lines values: {unexpected_lines}')
|
||||
@@ -6,49 +6,86 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
A sanity test for the built-in fixtures.
|
||||
Launch the windows launcher attached to the currently installed instance.
|
||||
"""
|
||||
# Import any dependencies for the test.
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
# Import any desired LTT modules from the package `ly_test_tools`. All LTT modules can be viewed at `Tools/LyTestTools/ly_test_tools`.
|
||||
import ly_test_tools
|
||||
# The `launchers.launcher_helper` module helps create Launcher objects which control the Open 3D Engine (O3DE) Editor and game clients.
|
||||
import ly_test_tools.launchers.launcher_helper as launcher_helper
|
||||
# The `builtin.helpers` module helps create the Workspace object, which controls the testing workspace in LTT.
|
||||
import ly_test_tools.builtin.helpers as helpers
|
||||
# The `environment` module contains tools that involve the system's environment such as processes or timed waiters.
|
||||
import ly_test_tools.environment.process_utils as process_utils
|
||||
import ly_test_tools.environment.waiter as waiter
|
||||
|
||||
pytestmark = pytest.mark.SUITE_smoke
|
||||
|
||||
# Initialize a logger instance to hook all test logs together. The sub-logger pattern below makes it easy to track which file creates a log line.
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Note: For device testing, device ids must exist in ~/ly_test_tools/devices.ini, see README.txt for more info.
|
||||
|
||||
|
||||
# First define the class `TestAutomatedTestingProject` to group test functions together.
|
||||
# The example test contains two test functions: `test_StartGameLauncher_Sanity` and `test_StartEditor_Sanity`.
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
# The example test utilizes Pytest parameterization. The following sets the `project` parameter to `AutomatedTesting`
|
||||
# for both test functions. Notice that the Pytest mark is defined at the class level to affect both test functions.
|
||||
class TestAutomatedTestingProject(object):
|
||||
|
||||
def test_StartGameLauncher_Sanity(self, project):
|
||||
"""
|
||||
The `test_StartGameLauncher_Sanity` test function verifies that the O3DE game client launches successfully.
|
||||
Start the test by utilizing the `kill_processes_named` function to close any open O3DE processes that may
|
||||
interfere with the test. The Workspace object emulates the O3DE package by locating the engine and project
|
||||
directories. The Launcher object controls the O3DE game client and requires a Workspace object for
|
||||
initialization. Add the `-rhi=Null` arg to the executable call to disable GPU rendering. This allows the
|
||||
test to run on instances without a GPU. We launch the game client executable and wait for the process to exist.
|
||||
A try/finally block ensures proper test cleanup if issues occur during the test.
|
||||
"""
|
||||
# Kill processes that may interfere with the test
|
||||
process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True)
|
||||
|
||||
try:
|
||||
# Create the Workspace object
|
||||
workspace = helpers.create_builtin_workspace(project=project)
|
||||
|
||||
# Create the Launcher object and add args
|
||||
launcher = launcher_helper.create_launcher(workspace)
|
||||
launcher.args.extend(['-NullRenderer', '-BatchMode'])
|
||||
launcher.args.extend(['-rhi=Null'])
|
||||
|
||||
# Call the game client executable
|
||||
with launcher.start():
|
||||
# Wait for the process to exist
|
||||
waiter.wait_for(lambda: process_utils.process_exists(f"{project}.GameLauncher.exe", ignore_extensions=True))
|
||||
finally:
|
||||
# Clean up processes after the test is finished
|
||||
process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True)
|
||||
|
||||
@pytest.mark.skipif(not ly_test_tools.WINDOWS, reason="Editor currently only functions on Windows")
|
||||
def test_StartEditor_Sanity(self, project):
|
||||
"""
|
||||
The `test_StartEditor_Sanity` test function is similar to the previous example with minor adjustments. A
|
||||
PyTest mark skips the test if the operating system is not Windows. We use the `create_editor` function instead
|
||||
of `create_launcher` to create an Editor type launcher instead of a game client type launcher. The additional
|
||||
`-autotest_mode` arg supresses modal dialogs from interfering with our test. We launch the Editor executable and
|
||||
wait for the process to exist.
|
||||
"""
|
||||
# Kill processes that may interfere with the test
|
||||
process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True)
|
||||
|
||||
try:
|
||||
# Create the Workspace object
|
||||
workspace = helpers.create_builtin_workspace(project=project)
|
||||
|
||||
# Create the Launcher object and add args
|
||||
editor = launcher_helper.create_editor(workspace)
|
||||
editor.args.extend(['-NullRenderer', '-autotest_mode'])
|
||||
editor.args.extend(['-rhi=Null', '-autotest_mode'])
|
||||
|
||||
# Call the Editor executable
|
||||
with editor.start():
|
||||
# Wait for the process to exist
|
||||
waiter.wait_for(lambda: process_utils.process_exists("Editor", ignore_extensions=True))
|
||||
finally:
|
||||
# Clean up processes after the test is finished
|
||||
process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True)
|
||||
|
||||
@@ -100,18 +100,29 @@ function(ly_setup_target OUTPUT_CONFIGURED_TARGET ALIAS_TARGET_NAME absolute_tar
|
||||
cmake_path(RELATIVE_PATH target_library_output_directory BASE_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} OUTPUT_VARIABLE target_library_output_subdirectory)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS ${TARGET_NAME}
|
||||
ARCHIVE
|
||||
DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>
|
||||
COMPONENT ${install_component}
|
||||
LIBRARY
|
||||
DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}
|
||||
COMPONENT ${install_component}
|
||||
RUNTIME
|
||||
DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_runtime_output_subdirectory}
|
||||
COMPONENT ${install_component}
|
||||
)
|
||||
if(COMMAND ly_install_target_override)
|
||||
# Mac needs special handling because of a cmake issue
|
||||
ly_install_target_override(TARGET ${TARGET_NAME}
|
||||
ARCHIVE_DIR ${archive_output_directory}
|
||||
LIBRARY_DIR ${library_output_directory}
|
||||
RUNTIME_DIR ${runtime_output_directory}
|
||||
LIBRARY_SUBDIR ${target_library_output_subdirectory}
|
||||
RUNTIME_SUBDIR ${target_runtime_output_subdirectory}
|
||||
)
|
||||
else()
|
||||
install(
|
||||
TARGETS ${TARGET_NAME}
|
||||
ARCHIVE
|
||||
DESTINATION ${archive_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>
|
||||
COMPONENT ${install_component}
|
||||
LIBRARY
|
||||
DESTINATION ${library_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_library_output_subdirectory}
|
||||
COMPONENT ${install_component}
|
||||
RUNTIME
|
||||
DESTINATION ${runtime_output_directory}/${PAL_PLATFORM_NAME}/$<CONFIG>/${target_runtime_output_subdirectory}
|
||||
COMPONENT ${install_component}
|
||||
)
|
||||
endif()
|
||||
|
||||
# CMakeLists.txt file
|
||||
string(REGEX MATCH "(.*)::(.*)$" match ${ALIAS_TARGET_NAME})
|
||||
@@ -487,7 +498,7 @@ function(ly_setup_others)
|
||||
|
||||
# Scripts
|
||||
file(GLOB o3de_scripts "${LY_ROOT_FOLDER}/scripts/o3de.*")
|
||||
install(FILES
|
||||
install(PROGRAMS
|
||||
${o3de_scripts}
|
||||
DESTINATION ./scripts
|
||||
)
|
||||
@@ -505,6 +516,14 @@ function(ly_setup_others)
|
||||
DESTINATION .
|
||||
REGEX "downloaded_packages" EXCLUDE
|
||||
REGEX "runtime" EXCLUDE
|
||||
REGEX ".*$\.sh" EXCLUDE
|
||||
)
|
||||
|
||||
# For Mac/Linux shell scripts need to be installed as PROGRAMS to have execute permission
|
||||
file(GLOB python_scripts "${LY_ROOT_FOLDER}/python/*.sh")
|
||||
install(PROGRAMS
|
||||
${python_scripts}
|
||||
DESTINATION ./python
|
||||
)
|
||||
|
||||
# Registry
|
||||
|
||||
@@ -28,7 +28,9 @@ else()
|
||||
endif()
|
||||
|
||||
# Signing
|
||||
ly_set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS --deep)
|
||||
# The "-o linker-signed" flag is required as a work-around for the following CMake issue:
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/issues/21854
|
||||
ly_set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "--deep -o linker-signed")
|
||||
|
||||
# Generate scheme files for Xcode
|
||||
ly_set(CMAKE_XCODE_GENERATE_SCHEME TRUE)
|
||||
|
||||
@@ -5,7 +5,47 @@
|
||||
#
|
||||
#
|
||||
|
||||
# Empty implementations for untested platforms to fix build errors.
|
||||
#! ly_install_target_override: Mac specific target installation
|
||||
function(ly_install_target_override)
|
||||
|
||||
function(ly_setup_o3de_install)
|
||||
endfunction()
|
||||
set(options)
|
||||
set(oneValueArgs TARGET ARCHIVE_DIR LIBRARY_DIR RUNTIME_DIR LIBRARY_SUBDIR RUNTIME_SUBDIR)
|
||||
set(multiValueArgs)
|
||||
cmake_parse_arguments(ly_platform_install_target "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
get_property(install_component TARGET ${ly_platform_install_target_TARGET} PROPERTY INSTALL_COMPONENT)
|
||||
|
||||
# For bundles on Mac, we set the icons by passing in a path to the Images.xcassets directory.
|
||||
# However, the CMake install command expects paths to files for the the RESOURCE property.
|
||||
# More details can be found in the CMake issue: https://gitlab.kitware.com/cmake/cmake/-/issues/22409
|
||||
get_target_property(is_bundle ${ly_platform_install_target_TARGET} MACOSX_BUNDLE)
|
||||
if (${is_bundle})
|
||||
get_target_property(cached_resources_dir ${ly_platform_install_target_TARGET} RESOURCE)
|
||||
set_property(TARGET ${ly_platform_install_target_TARGET} PROPERTY RESOURCE "")
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS ${ly_platform_install_target_TARGET}
|
||||
ARCHIVE
|
||||
DESTINATION ${ly_platform_install_target_ARCHIVE_DIR}/${PAL_PLATFORM_NAME}/$<CONFIG>
|
||||
COMPONENT ${install_component}
|
||||
LIBRARY
|
||||
DESTINATION ${ly_platform_install_target_LIBRARY_DIR}/${PAL_PLATFORM_NAME}/$<CONFIG>/${ly_platform_install_target_LIBRARY_SUBDIR}
|
||||
COMPONENT ${install_component}
|
||||
RUNTIME
|
||||
DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${PAL_PLATFORM_NAME}/$<CONFIG>/${ly_platform_install_target_RUNTIME_SUBDIR}
|
||||
COMPONENT ${install_component}
|
||||
BUNDLE
|
||||
DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${PAL_PLATFORM_NAME}/$<CONFIG>/${ly_platform_install_target_RUNTIME_SUBDIR}
|
||||
COMPONENT ${install_component}
|
||||
RESOURCE
|
||||
DESTINATION ${ly_platform_install_target_RUNTIME_DIR}/${PAL_PLATFORM_NAME}/$<CONFIG>/${ly_platform_install_target_RUNTIME_SUBDIR}/
|
||||
COMPONENT ${install_component}
|
||||
)
|
||||
|
||||
if (${is_bundle})
|
||||
set_property(TARGET ${ly_platform_install_target_TARGET} PROPERTY RESOURCE ${cached_resources_dir})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
include(cmake/Platform/Common/Install_common.cmake)
|
||||
|
||||
Reference in New Issue
Block a user