Merge branch 'development' into redcode/driller_removal

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

# Conflicts:
#	Code/Framework/AzCore/AzCore/azcore_files.cmake
#	Gems/Atom/Feature/Common/Assets/Materials/Presets/MacBeth/15_red_sRGB.tif
monroegm-disable-blank-issue-2
Esteban Papp 4 years ago
commit 5cca52e73c

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:011454252e40c927343cce16296412f02f45d1f345c75c036651bdcca473bda5
size 2672

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7bafcc4aefab827e1414e64bcdde235500b51392e52c9ccd588b2d7a24b865a0
size 20214

@ -1,46 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
import ly_test_tools.environment.file_system as file_system
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
from .atom_utils.atom_component_helper import create_screenshots_archive, golden_images_directory
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAutomation(EditorTestSuite):
# Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests.
global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"]
enable_prefab_system = False
@pytest.mark.test_case_id("C34603773")
class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest):
use_null_renderer = False # Default is True
screenshot_name = "AtomBasicLevelSetup.ppm"
test_screenshots = [] # Gets set by setup()
screenshot_directory = "" # Gets set by setup()
# Clear existing test screenshots before starting test.
def setup(self, workspace):
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)]
file_system.delete(test_screenshots, True, True)
from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module
golden_images = [os.path.join(golden_images_directory(), screenshot_name)]
for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
compare_screenshots(test_screenshot, golden_screenshot)
create_screenshots_archive(screenshot_directory)

@ -1,200 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper
from Atom.atom_utils.screenshot_utils import ScreenshotHelper
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
DEGREE_RADIAN_FACTOR = 0.0174533
helper = EditorTestHelper(log_prefix="Test_Atom_BasicLevelSetup")
def run():
"""
1. View -> Layouts -> Restore Default Layout, sets the viewport to ratio 16:9 @ 1280 x 720
2. Runs console command r_DisplayInfo = 0
3. Deletes all entities currently present in the level.
4. Creates a "default_level" entity to hold all other entities, setting the translate values to x:0, y:0, z:0
5. Adds a Grid component to the "default_level" & updates its Grid Spacing to 1.0m
6. Adds a "global_skylight" entity to "default_level", attaching an HDRi Skybox w/ a Cubemap Texture.
7. Adds a Global Skylight (IBL) component w/ diffuse image and specular image to "global_skylight" entity.
8. Adds a "ground_plane" entity to "default_level", attaching a Mesh component & Material component.
9. Adds a "directional_light" entity to "default_level" & adds a Directional Light component.
10. Adds a "sphere" entity to "default_level" & adds a Mesh component with a Material component to it.
11. Adds a "camera" entity to "default_level" & adds a Camera component with 80 degree FOV and Transform values:
Translate - x:5.5m, y:-12.0m, z:9.0m
Rotate - x:-27.0, y:-12.0, z:25.0
12. Finally enters game mode, takes a screenshot, & exits game mode.
:return: None
"""
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.camera as camera
import azlmbr.entity as entity
import azlmbr.legacy.general as general
import azlmbr.math as math
import azlmbr.paths
import azlmbr.editor as editor
def initial_viewport_setup(screen_width, screen_height):
general.set_viewport_size(screen_width, screen_height)
general.update_viewport()
helper.wait_for_condition(
function=lambda: helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1)
and helper.isclose(a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1),
timeout_in_seconds=4.0
)
result = helper.isclose(a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and helper.isclose(
a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1)
general.log(general.get_viewport_size().x)
general.log(general.get_viewport_size().y)
general.log(general.get_viewport_size().z)
general.log(f"Viewport is set to the expected size: {result}")
general.run_console("r_DisplayInfo = 0")
def after_level_load():
"""Function to call after creating/opening a level to ensure it loads."""
# Give everything a second to initialize.
general.idle_enable(True)
general.idle_wait(1.0)
general.update_viewport()
general.idle_wait(0.5) # half a second is more than enough for updating the viewport.
# Close out problematic windows, FPS meters, and anti-aliasing.
if general.is_helpers_shown(): # Turn off the helper gizmos if visible
general.toggle_helpers()
general.idle_wait(1.0)
if general.is_pane_visible("Error Report"): # Close Error Report windows that block focus.
general.close_pane("Error Report")
if general.is_pane_visible("Error Log"): # Close Error Log windows that block focus.
general.close_pane("Error Log")
general.idle_wait(1.0)
general.run_console("r_displayInfo=0")
general.idle_wait(1.0)
# Wait for Editor idle loop before executing Python hydra scripts.
general.idle_enable(True)
# Basic setup for opened level.
helper.open_level(level_name="Base")
after_level_load()
initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT)
# Create default_level entity
search_filter = azlmbr.entity.SearchFilter()
all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities)
default_level = hydra.Entity("default_level")
position = math.Vector3(0.0, 0.0, 0.0)
default_level.create_entity(position, ["Grid"])
default_level.get_set_test(0, "Controller|Configuration|Secondary Grid Spacing", 1.0)
# Create global_skylight entity and set the properties
global_skylight = hydra.Entity("global_skylight")
global_skylight.create_entity(
entity_position=math.Vector3(0.0, 0.0, 0.0),
components=["HDRi Skybox", "Global Skylight (IBL)"],
parent_id=default_level.id
)
global_skylight_image_asset_path = os.path.join("LightingPresets", "default_iblskyboxcm.exr.streamingimage")
global_skylight_image_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", global_skylight_image_asset_path, math.Uuid(), False)
global_skylight.get_set_test(0, "Controller|Configuration|Cubemap Texture", global_skylight_image_asset)
hydra.get_set_test(global_skylight, 1, "Controller|Configuration|Diffuse Image", global_skylight_image_asset)
hydra.get_set_test(global_skylight, 1, "Controller|Configuration|Specular Image", global_skylight_image_asset)
# Create ground_plane entity and set the properties
ground_plane = hydra.Entity("ground_plane")
ground_plane.create_entity(
entity_position=math.Vector3(0.0, 0.0, 0.0),
components=["Material"],
parent_id=default_level.id
)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0)
# Work around to add the correct Atom Mesh component and asset.
mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId
ground_plane.components.append(
editor.EditorComponentAPIBus(
bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id]
).GetValue()[0]
)
ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel")
ground_plane_mesh_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False)
hydra.get_set_test(ground_plane, 1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset)
# Add Atom Material component and asset.
ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial")
ground_plane_material_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False)
ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset)
# Create directional_light entity and set the properties
directional_light = hydra.Entity("directional_light")
directional_light.create_entity(
entity_position=math.Vector3(0.0, 0.0, 10.0),
components=["Directional Light"],
parent_id=default_level.id
)
rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", directional_light.id, rotation)
# Create sphere entity and set the properties
sphere = hydra.Entity("sphere")
sphere.create_entity(
entity_position=math.Vector3(0.0, 0.0, 1.0),
components=["Material"],
parent_id=default_level.id
)
# Work around to add the correct Atom Mesh component and asset.
sphere.components.append(
editor.EditorComponentAPIBus(
bus.Broadcast, "AddComponentsOfType", sphere.id, [mesh_type_id]
).GetValue()[0]
)
sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel")
sphere_mesh_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False)
hydra.get_set_test(sphere, 1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset)
# Add Atom Material component and asset.
sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial")
sphere_material_asset = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False)
sphere.get_set_test(0, "Default Material|Material Asset", sphere_material_asset)
# Create camera component and set the properties
camera_entity = hydra.Entity("camera")
position = math.Vector3(5.5, -12.0, 9.0)
camera_entity.create_entity(components=["Camera"], entity_position=position, parent_id=default_level.id)
rotation = math.Vector3(
DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0
)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation)
camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0)
camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
# Enter game mode, take screenshot, & exit game mode.
general.idle_wait(0.5)
general.enter_game_mode()
general.idle_wait(1.0)
helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=2.0)
ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(f"{'AtomBasicLevelSetup'}.ppm")
general.exit_game_mode()
helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=2.0)
if __name__ == "__main__":
run()

@ -1,261 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import sys
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.math as math
import azlmbr.paths
import azlmbr.legacy.general as general
sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
LEVEL_NAME = "Base"
LIGHT_COMPONENT = "Light"
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
DEGREE_RADIAN_FACTOR = 0.0174533
def run():
"""
Sets up the tests by making sure the required level is created & setup correctly.
It then executes 2 test cases - see each associated test function's docstring for more info.
Finally prints the string "Light component tests completed" after completion
Tests will fail immediately if any of these log lines are found:
1. Trace::Assert
2. Trace::Error
3. Traceback (most recent call last):
:return: None
"""
atom_component_helper.create_basic_atom_level(level_name=LEVEL_NAME)
# Run tests.
area_light_test()
spot_light_test()
general.log("Light component tests completed.")
def area_light_test():
"""
Basic test for the "Light" component attached to an "area_light" entity.
Test Case - Light Component: Capsule, Spot (disk), and Point (sphere):
1. Creates "area_light" entity w/ a Light component that has a Capsule Light type w/ the color set to 255, 0, 0
2. Enters game mode to take a screenshot for comparison, then exits game mode.
3. Sets the Light component Intensity Mode to Lumens (default).
4. Ensures the Light component Mode is Automatic (default).
5. Sets the Intensity value of the Light component to 0.0
6. Enters game mode again, takes another screenshot for comparison, then exits game mode.
7. Updates the Intensity value of the Light component to 1000.0
8. Enters game mode again, takes another screenshot for comparison, then exits game mode.
9. Swaps the Capsule light type option to Spot (disk) light type on the Light component
10. Updates "area_light" entity Transform rotate value to x: 90.0, y:0.0, z:0.0
11. Enters game mode again, takes another screenshot for comparison, then exits game mode.
12. Swaps the Spot (disk) light type for the Point (sphere) light type in the Light component.
13. Enters game mode again, takes another screenshot for comparison, then exits game mode.
14. Deletes the Light component from the "area_light" entity and verifies its successful.
"""
# Create an "area_light" entity with "Light" component using Light type of "Capsule"
area_light_entity_name = "area_light"
area_light = hydra.Entity(area_light_entity_name)
area_light.create_entity(math.Vector3(-1.0, -2.0, 3.0), [LIGHT_COMPONENT])
general.log(
f"{area_light_entity_name}_test: Component added to the entity: "
f"{hydra.has_components(area_light.id, [LIGHT_COMPONENT])}")
light_component_id_pair = hydra.attach_component_to_entity(area_light.id, LIGHT_COMPONENT)
# Select the "Capsule" light type option.
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_id_pair,
LIGHT_TYPE_PROPERTY,
atom_constants.LIGHT_TYPES['capsule']
)
# Update color and take screenshot in game mode
color = math.Color(255.0, 0.0, 0.0, 0.0)
area_light.get_set_test(0, "Controller|Configuration|Color", color)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("AreaLight_1", area_light_entity_name)
# Update intensity value to 0.0 and take screenshot in game mode
area_light.get_set_test(0, "Controller|Configuration|Attenuation Radius|Mode", 1)
area_light.get_set_test(0, "Controller|Configuration|Intensity", 0.0)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("AreaLight_2", area_light_entity_name)
# Update intensity value to 1000.0 and take screenshot in game mode
area_light.get_set_test(0, "Controller|Configuration|Intensity", 1000.0)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("AreaLight_3", area_light_entity_name)
# Swap the "Capsule" light type option to "Spot (disk)" light type
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_id_pair,
LIGHT_TYPE_PROPERTY,
atom_constants.LIGHT_TYPES['spot_disk']
)
area_light_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * 90.0, 0.0, 0.0)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", area_light.id, area_light_rotation)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("AreaLight_4", area_light_entity_name)
# Swap the "Spot (disk)" light type to the "Point (sphere)" light type and take screenshot.
azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_id_pair,
LIGHT_TYPE_PROPERTY,
atom_constants.LIGHT_TYPES['sphere']
)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("AreaLight_5", area_light_entity_name)
editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", area_light.id)
def spot_light_test():
"""
Basic test for the Light component attached to a "spot_light" entity.
Test Case - Light Component: Spot (disk) with shadows & colors:
1. Creates "spot_light" entity w/ a Light component attached to it.
2. Selects the "directional_light" entity already present in the level and disables it.
3. Selects the "global_skylight" entity already present in the level and disables the HDRi Skybox component,
as well as the Global Skylight (IBL) component.
4. Enters game mode to take a screenshot for comparison, then exits game mode.
5. Selects the "ground_plane" entity and changes updates the material to a new material.
6. Enters game mode to take a screenshot for comparison, then exits game mode.
7. Selects the "spot_light" entity and increases the Light component Intensity to 800 lm
8. Enters game mode to take a screenshot for comparison, then exits game mode.
9. Selects the "spot_light" entity and sets the Light component Color to 47, 75, 37
10. Enters game mode to take a screenshot for comparison, then exits game mode.
11. Selects the "spot_light" entity and modifies the Shutter controls to the following values:
- Enable shutters: True
- Inner Angle: 60.0
- Outer Angle: 75.0
12. Enters game mode to take a screenshot for comparison, then exits game mode.
13. Selects the "spot_light" entity and modifies the Shadow controls to the following values:
- Enable Shadow: True
- ShadowmapSize: 256
14. Modifies the world translate position of the "spot_light" entity to 0.7, -2.0, 1.9 (for casting shadows better)
15. Enters game mode to take a screenshot for comparison, then exits game mode.
"""
# Disable "Directional Light" component for the "directional_light" entity
# "directional_light" entity is created by the create_basic_atom_level() function by default.
directional_light_entity_id = hydra.find_entity_by_name("directional_light")
directional_light = hydra.Entity(name='directional_light', id=directional_light_entity_id)
directional_light_component_type = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Directional Light"], 0)[0]
directional_light_component = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'GetComponentOfType', directional_light.id, directional_light_component_type
).GetValue()
editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [directional_light_component])
general.idle_wait(0.5)
# Disable "Global Skylight (IBL)" and "HDRi Skybox" components for the "global_skylight" entity
global_skylight_entity_id = hydra.find_entity_by_name("global_skylight")
global_skylight = hydra.Entity(name='global_skylight', id=global_skylight_entity_id)
global_skylight_component_type = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Global Skylight (IBL)"], 0)[0]
global_skylight_component = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'GetComponentOfType', global_skylight.id, global_skylight_component_type
).GetValue()
editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [global_skylight_component])
hdri_skybox_component_type = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["HDRi Skybox"], 0)[0]
hdri_skybox_component = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'GetComponentOfType', global_skylight.id, hdri_skybox_component_type
).GetValue()
editor.EditorComponentAPIBus(bus.Broadcast, "DisableComponents", [hdri_skybox_component])
general.idle_wait(0.5)
# Create a "spot_light" entity with "Light" component using Light Type of "Spot (disk)"
spot_light_entity_name = "spot_light"
spot_light = hydra.Entity(spot_light_entity_name)
spot_light.create_entity(math.Vector3(0.7, -2.0, 1.0), [LIGHT_COMPONENT])
general.log(
f"{spot_light_entity_name}_test: Component added to the entity: "
f"{hydra.has_components(spot_light.id, [LIGHT_COMPONENT])}")
rotation = math.Vector3(DEGREE_RADIAN_FACTOR * 300.0, 0.0, 0.0)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", spot_light.id, rotation)
light_component_type = hydra.attach_component_to_entity(spot_light.id, LIGHT_COMPONENT)
editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
light_component_type,
LIGHT_TYPE_PROPERTY,
atom_constants.LIGHT_TYPES['spot_disk']
)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("SpotLight_1", spot_light_entity_name)
# Change default material of ground plane entity and take screenshot
ground_plane_entity_id = hydra.find_entity_by_name("ground_plane")
ground_plane = hydra.Entity(name='ground_plane', id=ground_plane_entity_id)
ground_plane_asset_path = os.path.join("Materials", "Presets", "MacBeth", "22_neutral_5-0_0-70d.azmaterial")
ground_plane_asset_value = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", ground_plane_asset_path, math.Uuid(), False)
material_property_path = "Default Material|Material Asset"
material_component_type = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Material"], 0)[0]
material_component = azlmbr.editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast, 'GetComponentOfType', ground_plane.id, material_component_type).GetValue()
editor.EditorComponentAPIBus(
azlmbr.bus.Broadcast,
'SetComponentProperty',
material_component,
material_property_path,
ground_plane_asset_value
)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("SpotLight_2", spot_light_entity_name)
# Increase intensity value of the Spot light and take screenshot in game mode
spot_light.get_set_test(0, "Controller|Configuration|Intensity", 800.0)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("SpotLight_3", spot_light_entity_name)
# Update the Spot light color and take screenshot in game mode
color_value = math.Color(47.0 / 255.0, 75.0 / 255.0, 37.0 / 255.0, 255.0 / 255.0)
spot_light.get_set_test(0, "Controller|Configuration|Color", color_value)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("SpotLight_4", spot_light_entity_name)
# Update the Shutter controls of the Light component and take screenshot
spot_light.get_set_test(0, "Controller|Configuration|Shutters|Enable shutters", True)
spot_light.get_set_test(0, "Controller|Configuration|Shutters|Inner angle", 60.0)
spot_light.get_set_test(0, "Controller|Configuration|Shutters|Outer angle", 75.0)
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("SpotLight_5", spot_light_entity_name)
# Update the Shadow controls, move the spot_light entity world translate position and take screenshot
spot_light.get_set_test(0, "Controller|Configuration|Shadows|Enable shadow", True)
spot_light.get_set_test(0, "Controller|Configuration|Shadows|Shadowmap size", 256.0)
azlmbr.components.TransformBus(
azlmbr.bus.Event, "SetWorldTranslation", spot_light.id, math.Vector3(0.7, -2.0, 1.9))
general.idle_wait(1.0)
screenshot_utils.take_screenshot_game_mode("SpotLight_6", spot_light_entity_name)
if __name__ == "__main__":
run()

@ -113,8 +113,15 @@ set(FILES
Debug/TraceMessageBus.h
Debug/TraceReflection.cpp
Debug/TraceReflection.h
DOM/DomBackend.cpp
DOM/DomBackend.h
DOM/DomUtils.cpp
DOM/DomUtils.h
DOM/DomVisitor.cpp
DOM/DomVisitor.h
DOM/Backends/JSON/JsonBackend.h
DOM/Backends/JSON/JsonSerializationUtils.cpp
DOM/Backends/JSON/JsonSerializationUtils.h
EBus/BusImpl.h
EBus/EBus.h
EBus/EBusEnvironment.cpp

@ -212,6 +212,8 @@ set(FILES
AZStd/Variant.cpp
AZStd/VariantSerialization.cpp
AZStd/VectorAndArray.cpp
DOM/DomJsonTests.cpp
DOM/DomJsonBenchmarks.cpp
)
# Prevent the following files from being grouped in UNITY builds

@ -18,7 +18,10 @@
#include <AzFramework/Components/TransformComponent.h>
#include <AzToolsFramework/Application/ToolsApplication.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <AzToolsFramework/ToolsComponents/TransformComponent.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <Prefab/PrefabTestFixture.h>
#include <AZTestShared/Math/MathTestHelpers.h>
@ -1062,4 +1065,67 @@ R"DELIMITER(<ObjectStream version="1">
}
}
}
// Fixture provides a root prefab with Transform component and listens for TransformNotificationBus.
class TransformComponentActivationTest
: public PrefabTestFixture
, public TransformNotificationBus::Handler
{
protected:
void SetUpEditorFixtureImpl() override
{
PrefabTestFixture::SetUpEditorFixtureImpl();
CreateRootPrefab();
}
void TearDownEditorFixtureImpl() override
{
BusDisconnect();
PrefabTestFixture::TearDownEditorFixtureImpl();
}
void OnTransformChanged(const Transform& /*local*/, const Transform& /*world*/) override
{
m_transformUpdated = true;
}
void MoveEntity(AZ::EntityId entityId)
{
AzToolsFramework::ScopedUndoBatch undoBatch("Move Entity");
TransformBus::Event(entityId, &TransformInterface::SetWorldTranslation, Vector3(1.f, 0.f, 0.f));
}
bool m_transformUpdated = false;
};
TEST_F(TransformComponentActivationTest, TransformChangedEventIsSentWhenEntityIsActivatedViaUndoRedo)
{
AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity");
MoveEntity(entityId);
BusConnect(entityId);
// verify that undoing/redoing move operations fires TransformChanged event
Undo();
EXPECT_TRUE(m_transformUpdated);
m_transformUpdated = false;
Redo();
EXPECT_TRUE(m_transformUpdated);
m_transformUpdated = false;
}
TEST_F(TransformComponentActivationTest, TransformChangedEventIsNotSentWhenEntityIsDeactivatedAndActivated)
{
AZ::EntityId entityId = CreateEntityUnderRootPrefab("Entity");
BusConnect(entityId);
// verify that simply activating/deactivating an entity does not fire TransformChanged event
Entity* entity = nullptr;
ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
entity->Deactivate();
entity->Activate();
EXPECT_FALSE(m_transformUpdated);
}
} // namespace UnitTest

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b53b8ca6b7062239398820aef6fb4145a0b6c8c7e3aae90c17b6b87f806d3579
size 19426

@ -670,8 +670,6 @@ namespace AZ
AZ::u8 width,
int32_t viewProjOverrideIndex)
{
AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon");
// grab a mutex lock for the rest of this function so that a commit cannot happen during it and
// other threads can't add geometry during it
AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
@ -742,8 +740,6 @@ namespace AZ
AZ::u8 width,
int32_t viewProjOverrideIndex)
{
AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: DrawPrimitiveWithSharedVerticesCommon");
AZ_Assert(indexCount >= verticesPerPrimitiveType && (indexCount % verticesPerPrimitiveType == 0),
"Index count must be at least %d and must be a multiple of %d",
verticesPerPrimitiveType, verticesPerPrimitiveType);

@ -76,8 +76,8 @@ namespace AZ
void MeshFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
{
AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Simulate");
AZ_UNUSED(packet);
AZ::Job* parentJob = packet.m_parentJob;
AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
const auto iteratorRanges = m_modelData.GetParallelRanges();
@ -86,6 +86,8 @@ namespace AZ
{
const auto jobLambda = [&]() -> void
{
AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: Job");
for (auto meshDataIter = iteratorRange.first; meshDataIter != iteratorRange.second; ++meshDataIter)
{
if (!meshDataIter->m_model)
@ -113,24 +115,22 @@ namespace AZ
{
meshDataIter->BuildCullable();
}
if (meshDataIter->m_cullBoundsNeedsUpdate)
{
meshDataIter->UpdateCullBounds(m_transformService);
}
}
};
Job* executeGroupJob = aznew JobFunction<decltype(jobLambda)>(jobLambda, true, nullptr); // Auto-deletes
executeGroupJob->SetDependent(&jobCompletion);
executeGroupJob->Start();
parentJob->StartAsChild(executeGroupJob);
}
jobCompletion.StartAndWaitForCompletion();
m_forceRebuildDrawPackets = false;
// CullingSystem::RegisterOrUpdateCullable() is not threadsafe, so need to do those updates in a single thread
for (ModelDataInstance& modelDataInstance : m_modelData)
{
if (modelDataInstance.m_model && modelDataInstance.m_cullBoundsNeedsUpdate)
{
modelDataInstance.UpdateCullBounds(m_transformService);
}
AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: WaitForChildren");
parentJob->WaitForChildren();
}
m_forceRebuildDrawPackets = false;
}
void MeshFeatureProcessor::OnBeginPrepareRender()
@ -1037,7 +1037,6 @@ namespace AZ
void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
{
AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance:: UpdateDrawPackets");
for (auto& drawPacketList : m_drawPacketListsByLod)
{
for (auto& drawPacket : drawPacketList)
@ -1052,7 +1051,6 @@ namespace AZ
void ModelDataInstance::BuildCullable()
{
AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: BuildCullable");
AZ_Assert(m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");
@ -1129,7 +1127,6 @@ namespace AZ
void ModelDataInstance::UpdateCullBounds(const TransformServiceFeatureProcessor* transformService)
{
AZ_PROFILE_SCOPE(AzRender, "ModelDataInstance: UpdateCullBounds");
AZ_Assert(m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt");
AZ_Assert(m_model, "The model has not finished loading yet");

@ -232,9 +232,10 @@ namespace AZ
for (ScopeProducer* scopeProducer : m_scopeProducers)
{
AZ_PROFILE_SCOPE(RHI, "FrameScheduler: PrepareProducers: Scope %s", scopeProducer->GetScopeId().GetCStr());
m_frameGraph->BeginScope(*scopeProducer->GetScope());
scopeProducer->SetupFrameGraphDependencies(*m_frameGraph);
// All scopes depend on the root scope.
if (scopeProducer->GetScopeId() != m_rootScopeId)
{
@ -526,7 +527,10 @@ namespace AZ
parentJob->StartAsChild(AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr));
}
parentJob->WaitForChildren();
{
AZ_PROFILE_SCOPE(RHI, "FrameScheduler: ExecuteGroupInternal: WaitForChildren");
parentJob->WaitForChildren();
}
}
m_frameGraphExecuter->EndGroup(groupIndex);

@ -477,8 +477,7 @@ namespace AZ
return;
}
D3D12_RESOURCE_TRANSITION_BARRIER transition;
memset(&transition, 0, sizeof(D3D12_RESOURCE_TRANSITION_BARRIER)); // C4701 potentially unitialized local variable 'transition' used
D3D12_RESOURCE_TRANSITION_BARRIER transition = {0};
transition.pResource = image.GetMemoryView().GetMemory();
Scope& firstScope = static_cast<Scope&>(scopeAttachment->GetScope());

@ -92,13 +92,13 @@ namespace AZ
const bool Scope::IsStateSupportedByQueue(D3D12_RESOURCE_STATES state) const
{
const D3D12_RESOURCE_STATES VALID_COMPUTE_QUEUE_RESOURCE_STATES =
constexpr D3D12_RESOURCE_STATES VALID_COMPUTE_QUEUE_RESOURCE_STATES =
(D3D12_RESOURCE_STATE_UNORDERED_ACCESS |
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE |
D3D12_RESOURCE_STATE_COPY_DEST |
D3D12_RESOURCE_STATE_COPY_SOURCE);
const D3D12_RESOURCE_STATES VALID_GRAPHICS_QUEUE_RESOURCE_STATES =
constexpr D3D12_RESOURCE_STATES VALID_GRAPHICS_QUEUE_RESOURCE_STATES =
(D3D12_RESOURCE_STATES)DX12_RESOURCE_STATE_VALID_API_MASK;
switch (GetHardwareQueueClass())

@ -34,7 +34,7 @@
//Enables more detailed profiling descriptions within the culling system, but adds some performance overhead.
//Enable this to more easily see which jobs are associated with which view.
//#define AZ_CULL_PROFILE_VERBOSE
//#define AZ_CULL_PROFILE_VERBOSE
namespace AZ
{
@ -43,6 +43,7 @@ namespace AZ
AZ_CVAR(bool, r_CullInParallel, true, nullptr, ConsoleFunctorFlags::Null, "");
AZ_CVAR(uint32_t, r_CullWorkPerBatch, 500, nullptr, ConsoleFunctorFlags::Null, "");
#ifdef AZ_CULL_DEBUG_ENABLED
void DebugDrawWorldCoordinateAxes(AuxGeomDraw* auxGeom)
{
auxGeom->DrawCylinder(Vector3(.5, .0, .0), Vector3(1, 0, 0), 0.02f, 1.0f, Colors::Red, AuxGeomDraw::DrawStyle::Solid, AuxGeomDraw::DepthTest::Off);
@ -198,6 +199,7 @@ namespace AZ
AZ_Assert(false, "invalid frustum, cannot draw");
}
}
#endif //AZ_CULL_DEBUG_ENABLED
CullingDebugContext::~CullingDebugContext()
{
@ -282,7 +284,7 @@ namespace AZ
const Scene& scene,
View& view,
Frustum& frustum,
[[maybe_unused]]void* maskedOcclusionCulling)
[[maybe_unused]] void* maskedOcclusionCulling)
{
AZStd::shared_ptr<WorklistData> worklistData = AZStd::make_shared<WorklistData>();
worklistData->m_debugCtx = &debugCtx;
@ -318,14 +320,16 @@ namespace AZ
for (const AzFramework::IVisibilityScene::NodeData& nodeData : worklist)
{
//If a node is entirely contained within the frustum, then we can skip the fine grained culling.
bool nodeIsContainedInFrustum = ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds);
bool nodeIsContainedInFrustum =
!worklistData->m_debugCtx->m_enableFrustumCulling ||
ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds);
#ifdef AZ_CULL_PROFILE_VERBOSE
AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %d",
m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0);
AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %ds",
worklistData->m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? "true" : "false");
#endif
if (nodeIsContainedInFrustum || !worklistData->m_debugCtx->m_enableFrustumCulling)
if (nodeIsContainedInFrustum)
{
//Add all objects within this node to the view, without any extra culling
for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries)
@ -391,7 +395,7 @@ namespace AZ
}
}
}
#ifdef AZ_CULL_DEBUG_ENABLED
if (worklistData->m_debugCtx->m_debugDraw && (worklistData->m_view->GetName() == worklistData->m_debugCtx->m_currentViewSelectionName))
{
AZ_PROFILE_SCOPE(RPI, "debug draw culling");
@ -443,8 +447,10 @@ namespace AZ
}
}
}
#endif
}
#ifdef AZ_CULL_DEBUG_ENABLED
if (worklistData->m_debugCtx->m_enableStats)
{
CullingDebugContext::CullStats& cullStats = worklistData->m_debugCtx->GetCullStatsForView(worklistData->m_view);
@ -454,6 +460,7 @@ namespace AZ
cullStats.m_numVisibleCullables += numVisibleCullables;
++cullStats.m_numJobs;
}
#endif //AZ_CULL_DEBUG_ENABLED
}
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
@ -466,6 +473,10 @@ namespace AZ
return MaskedOcclusionCulling::CullingResult::VISIBLE;
}
#ifdef AZ_CULL_PROFILE_VERBOSE
AZ_PROFILE_SCOPE(RPI, "TestOcclusionCulling");
#endif
if (visibleEntry->m_boundingVolume.Contains(worklistData->m_view->GetCameraTransform().GetTranslation()))
{
// camera is inside bounding volume
@ -515,10 +526,15 @@ namespace AZ
}
#endif
void CullingScene::ProcessCullablesCommon(const Scene& scene, View& view, AZ::Frustum& frustum, [[maybe_unused]]void*& maskedOcclusionCulling)
void CullingScene::ProcessCullablesCommon(
const Scene& scene [[maybe_unused]],
View& view,
AZ::Frustum& frustum [[maybe_unused]],
void*& maskedOcclusionCulling [[maybe_unused]])
{
AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesCommon() - %s", view.GetName().GetCStr());
#ifdef AZ_CULL_DEBUG_ENABLED
if (m_debugCtx.m_freezeFrustums)
{
AZStd::lock_guard<AZStd::mutex> lock(m_debugCtx.m_frozenFrustumsMutex);
@ -543,7 +559,7 @@ namespace AZ
CullingDebugContext::CullStats& cullStats = m_debugCtx.GetCullStatsForView(&view);
cullStats.m_cameraViewToWorld = view.GetViewToWorldMatrix();
}
#endif //AZ_CULL_DEBUG_ENABLED
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
// setup occlusion culling, if necessary
maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling();
@ -805,6 +821,7 @@ namespace AZ
beginCullingDescriptor,
[&view]()
{
AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCullingTaskGraph");
view->BeginCulling();
});
}
@ -822,6 +839,7 @@ namespace AZ
{
const auto cullingLambda = [&view]()
{
AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCullingJob");
view->BeginCulling();
};
@ -843,7 +861,11 @@ namespace AZ
m_taskGraphActive = AZ::Interface<AZ::TaskGraphActiveInterface>::Get();
if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive())
if(views.size() == 1) // avoid job overhead when only 1 job
{
views[0]->BeginCulling();
}
else if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive())
{
BeginCullingTaskGraph(views);
}
@ -852,6 +874,7 @@ namespace AZ
BeginCullingJobs(views);
}
#if AZ_CULL_DEBUG_ENABLED
AuxGeomDrawPtr auxGeom;
if (m_debugCtx.m_debugDraw)
{
@ -884,6 +907,7 @@ namespace AZ
m_debugCtx.m_frozenFrustums.clear();
}
}
#endif
}
void CullingScene::EndCulling()

@ -311,7 +311,6 @@ namespace AZ
Pass::FramePrepareParams params{ &frameGraphBuilder };
{
AZ_PROFILE_SCOPE(RPI, "Pass: FrameBegin");
m_rootPass->FrameBegin(params);
}
}

@ -399,10 +399,11 @@ namespace AZ
for (FeatureProcessorPtr& fp : m_featureProcessors)
{
FeatureProcessor* featureProcessor = fp.get();
const auto jobLambda = [this, featureProcessor]()
const auto jobLambda = [this, featureProcessor](AZ::Job& owner)
{
featureProcessor->Simulate(m_simulatePacket);
FeatureProcessor::SimulatePacket jobPacket = m_simulatePacket;
jobPacket.m_parentJob = &owner;
featureProcessor->Simulate(jobPacket);
};
AZ::Job* simulationJob = AZ::CreateJobFunction(AZStd::move(jobLambda), true, nullptr); //auto-deletes
@ -515,7 +516,7 @@ namespace AZ
collectDrawPacketsTG.Submit(&collectDrawPacketsTGEvent);
// Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs if m_parallelOctreeTraversal)
bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal;
const bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal;
m_cullingScene->BeginCulling(m_renderPacket.m_views);
static const AZ::TaskDescriptor processCullablesDescriptor{"AZ::RPI::Scene::ProcessCullables", "Graphics"};
AZ::TaskGraphEvent processCullablesTGEvent;
@ -575,6 +576,7 @@ namespace AZ
}
// Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs)
const bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal;
m_cullingScene->BeginCulling(m_renderPacket.m_views);
for (ViewPtr& viewPtr : m_renderPacket.m_views)
{
@ -583,7 +585,7 @@ namespace AZ
m_cullingScene->ProcessCullablesJobs(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job
},
true, nullptr); //auto-deletes
if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal)
if (parallelOctreeTraversal)
{
processCullablesJob->SetDependent(collectDrawPacketsCompletion);
processCullablesJob->Start();
@ -730,20 +732,19 @@ namespace AZ
// Add dynamic draw data for all the views
if (m_dynamicDrawSystem)
{
AZ_PROFILE_SCOPE(RPI, "DynamicDraw SubmitDrawData");
m_dynamicDrawSystem->SubmitDrawData(this, m_renderPacket.m_views);
}
}
{
AZ_PROFILE_BEGIN(RPI, "FinalizeDrawLists");
if (jobPolicy == RHI::JobPolicy::Serial)
AZ_PROFILE_SCOPE(RPI, "FinalizeDrawLists");
if (jobPolicy == RHI::JobPolicy::Serial ||
m_renderPacket.m_views.size() <= 1) // FinalizeDrawListsX both immediately wait for the job to complete, skip job if only 1 job would be generated
{
for (auto& view : m_renderPacket.m_views)
{
view->FinalizeDrawLists();
}
AZ_PROFILE_END(RPI);
}
else
{
@ -755,7 +756,6 @@ namespace AZ
{
FinalizeDrawListsJobs();
}
AZ_PROFILE_END(RPI);
}
}

@ -74,7 +74,7 @@ namespace ScriptCanvasEditor
AZ_Assert(loadResult.m_runtimeAsset, "failed to load dependent asset");
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation for function failed"));
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath);
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_editorAsset.Path().c_str());
AZ_Assert(luaAssetOutcome.IsSuccess(), "failed to create Lua asset");
AZStd::string modulePath = namespacePath[0].data();
@ -111,18 +111,19 @@ namespace ScriptCanvasEditor
AZ_INLINE LoadTestGraphResult LoadTestGraph(AZStd::string_view graphPath)
{
AZ::Data::Asset<ScriptCanvasEditor::ScriptCanvasAsset> editorAsset;
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(editorAsset, &ScriptCanvasEditor::EditorAssetConversionBusTraits::LoadAsset, graphPath);
if (editorAsset.GetData())
if (auto loadFileOutcome = LoadFromFile(graphPath); loadFileOutcome.IsSuccess())
{
AZ::Outcome< AZ::Data::Asset<ScriptCanvas::RuntimeAsset>, AZStd::string> assetOutcome = AZ::Failure(AZStd::string("asset creation failed"));
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, editorAsset);
auto& source = loadFileOutcome.GetValue();
auto testableSource = SourceHandle(source, AZ::Uuid::CreateRandom(), source.Path().c_str());
AZ::Outcome<AZ::Data::Asset<ScriptCanvas::RuntimeAsset>, AZStd::string> assetOutcome(AZ::Failure(AZStd::string("asset create failed")));
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(assetOutcome
, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateRuntimeAsset, testableSource);
if (assetOutcome.IsSuccess())
{
LoadTestGraphResult result;
result.m_graphPath = graphPath;
result.m_editorAsset = editorAsset;
result.m_editorAsset = AZStd::move(testableSource);
result.m_runtimeAsset = assetOutcome.GetValue();
result.m_entity = AZStd::make_unique<AZ::Entity>("Loaded Graph");
return result;
@ -163,8 +164,7 @@ namespace ScriptCanvasEditor
reporter.SetExecutionMode(mode);
LoadTestGraphResult loadResult;
loadResult.m_graphPath = asset.GetHint().c_str();
loadResult.m_editorAsset = asset;
loadResult.m_editorAsset = SourceHandle(nullptr, assetId.m_guid, asset.GetHint());
AZ::EntityId scriptCanvasId;
loadResult.m_entity = AZStd::make_unique<AZ::Entity>("Loaded test graph");
loadResult.m_runtimeAsset = runtimeAsset;
@ -205,7 +205,8 @@ namespace ScriptCanvasEditor
{
ScopedOutputSuppression outputSuppressor;
AZ::Outcome<ScriptCanvas::Translation::LuaAssetResult, AZStd::string> luaAssetOutcome = AZ::Failure(AZStd::string("lua asset creation failed"));
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_graphPath);
ScriptCanvasEditor::EditorAssetConversionBus::BroadcastResult(luaAssetOutcome
, &ScriptCanvasEditor::EditorAssetConversionBusTraits::CreateLuaAsset, loadResult.m_editorAsset, loadResult.m_editorAsset.Path().c_str());
reporter.MarkParseAttemptMade();
if (luaAssetOutcome.IsSuccess())
@ -219,6 +220,8 @@ namespace ScriptCanvasEditor
{
RuntimeDataOverrides runtimeDataOverrides;
runtimeDataOverrides.m_runtimeAsset = loadResult.m_runtimeAsset;
runtimeDataOverrides.m_runtimeAsset.SetHint("original");
runtimeDataOverrides.m_runtimeAsset.Get()->m_runtimeData.m_script.SetHint("original");
#if defined(LINUX) //////////////////////////////////////////////////////////////////////////
// Temporarily disable testing on the Linux build until the file name casing discrepancy
@ -264,6 +267,10 @@ namespace ScriptCanvasEditor
RuntimeDataOverrides dependencyRuntimeDataOverrides;
dependencyRuntimeDataOverrides.m_runtimeAsset = dependency.runtimeAsset;
AZStd::string dependencyHint = AZStd::string::format("dependency_%d", index);
dependencyRuntimeDataOverrides.m_runtimeAsset.SetHint(dependencyHint);
dependencyRuntimeDataOverrides.m_runtimeAsset.Get()->m_runtimeData.m_script.SetHint(dependencyHint);
runtimeDataOverrides.m_dependencies.push_back(dependencyRuntimeDataOverrides);
RuntimeData& dependencyData = dependencyDataBuffer[index];

@ -52,7 +52,6 @@ namespace ScriptCanvasEditor
m_view->textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOn);
connect(m_view->scanButton, &QPushButton::pressed, this, &Controller::OnButtonPressScan);
connect(m_view->closeButton, &QPushButton::pressed, this, &Controller::OnButtonPressClose);
m_view->upgradeAllButton->setVisible(false);
connect(m_view->upgradeAllButton, &QPushButton::pressed, this, &Controller::OnButtonPressUpgrade);
m_view->progressBar->setValue(0);
m_view->progressBar->setVisible(false);
@ -103,9 +102,9 @@ namespace ScriptCanvasEditor
}
}
QList<QTableWidgetItem*> Controller::FindTableItems(const AZ::Data::AssetInfo& info)
QList<QTableWidgetItem*> Controller::FindTableItems(const SourceHandle& info)
{
return m_view->tableWidget->findItems(info.m_relativePath.c_str(), Qt::MatchFlag::MatchExactly);
return m_view->tableWidget->findItems(info.Path().c_str(), Qt::MatchFlag::MatchExactly);
}
void Controller::OnButtonPressClose()
@ -116,30 +115,20 @@ namespace ScriptCanvasEditor
void Controller::OnButtonPressScan()
{
// \todo move to another file
auto isUpToDate = [this](AZ::Data::Asset<AZ::Data::AssetData> asset)
auto isUpToDate = [this](const SourceHandle& asset)
{
AZ::Entity* scriptCanvasEntity = nullptr;
auto graphComponent = asset.Get();
if (asset.GetType() == azrtti_typeid<ScriptCanvasAsset>())
{
ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs<ScriptCanvasAsset>();
if (!scriptCanvasAsset)
{
AZ_Warning
(ScriptCanvas::k_VersionExplorerWindow.data()
, false
, "InspectAsset: %s, AsestData failed to return ScriptCanvasAsset"
, asset.GetHint().c_str());
return true;
}
scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity();
AZ_Assert(scriptCanvasEntity, "The Script Canvas asset must have a valid entity");
}
auto graphComponent = scriptCanvasEntity->FindComponent<ScriptCanvasEditor::Graph>();
AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component");
return !m_view->forceUpgrade->isChecked() && graphComponent->GetVersion().IsLatest();
AZ_Warning
( ScriptCanvas::k_VersionExplorerWindow.data()
, asset.Get() != nullptr
, "InspectAsset: %s, failed to load valid graph"
, asset.Path().c_str());
return graphComponent
&& (!graphComponent->GetVersion().IsLatest() || m_view->forceUpgrade->isChecked())
? ScanConfiguration::Filter::Include
: ScanConfiguration::Filter::Exclude;
};
ScanConfiguration config;
@ -155,59 +144,19 @@ namespace ScriptCanvasEditor
OnButtonPressUpgradeImplementation({});
}
void Controller::OnButtonPressUpgradeImplementation(const AZ::Data::AssetInfo& assetInfo)
void Controller::OnButtonPressUpgradeImplementation(const SourceHandle& assetInfo)
{
auto simpleUpdate = [this](AZ::Data::Asset<AZ::Data::AssetData> asset)
auto simpleUpdate = [this](SourceHandle& asset)
{
if (asset.GetType() == azrtti_typeid<ScriptCanvasAsset>())
{
ScriptCanvasAsset* scriptCanvasAsset = asset.GetAs<ScriptCanvasAsset>();
AZ_Assert(scriptCanvasAsset, "Unable to get the asset of ScriptCanvasAsset, but received type: %s"
, azrtti_typeid<ScriptCanvasAsset>().template ToString<AZStd::string>().c_str());
if (!scriptCanvasAsset)
{
return;
}
AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), asset.Get() != nullptr
, "The Script Canvas asset must have a Graph component");
AZ::Entity* scriptCanvasEntity = scriptCanvasAsset->GetScriptCanvasEntity();
AZ_Assert(scriptCanvasEntity, "View::UpgradeGraph The Script Canvas asset must have a valid entity");
if (!scriptCanvasEntity)
{
return;
}
AZ::Entity* queryEntity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(queryEntity, &AZ::ComponentApplicationRequests::FindEntity, scriptCanvasEntity->GetId());
if (queryEntity)
{
if (queryEntity->GetState() == AZ::Entity::State::Active)
{
queryEntity->Deactivate();
}
scriptCanvasEntity = queryEntity;
}
if (scriptCanvasEntity->GetState() == AZ::Entity::State::Constructed)
{
scriptCanvasEntity->Init();
}
if (scriptCanvasEntity->GetState() == AZ::Entity::State::Init)
{
scriptCanvasEntity->Activate();
}
AZ_Assert(scriptCanvasEntity->GetState() == AZ::Entity::State::Active, "Graph entity is not active");
auto graphComponent = scriptCanvasEntity->FindComponent<ScriptCanvasEditor::Graph>();
AZ_Assert(graphComponent, "The Script Canvas entity must have a Graph component");
if (graphComponent)
{
graphComponent->UpgradeGraph
(asset
, m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate
, m_view->verbose->isChecked());
}
if (asset.Get())
{
asset.Mod()->UpgradeGraph
( asset
, m_view->forceUpgrade->isChecked() ? Graph::UpgradeRequest::Forced : Graph::UpgradeRequest::IfOutOfDate
, m_view->verbose->isChecked());
}
};
@ -215,7 +164,7 @@ namespace ScriptCanvasEditor
{
int result = QMessageBox::No;
QMessageBox mb
(QMessageBox::Warning
( QMessageBox::Warning
, QObject::tr("Failed to Save Upgraded File")
, QObject::tr("The upgraded file could not be saved because the file is read only.\n"
"Do you want to make it writeable and overwrite it?")
@ -234,12 +183,12 @@ namespace ScriptCanvasEditor
ModelRequestsBus::Broadcast(&ModelRequestsTraits::Modify, config);
}
void Controller::OnButtonPressUpgradeSingle(const AZ::Data::AssetInfo& assetInfo)
void Controller::OnButtonPressUpgradeSingle(const SourceHandle& info)
{
OnButtonPressUpgradeImplementation(assetInfo);
OnButtonPressUpgradeImplementation(info);
}
void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const AZ::Data::AssetInfo& info)
void Controller::OnUpgradeModificationBegin([[maybe_unused]] const ModifyConfiguration& config, const SourceHandle& info)
{
for (auto* item : FindTableItems(info))
{
@ -251,16 +200,16 @@ namespace ScriptCanvasEditor
void Controller::OnUpgradeModificationEnd
( [[maybe_unused]] const ModifyConfiguration& config
, const AZ::Data::AssetInfo& info
, const SourceHandle& info
, ModificationResult result)
{
if (result.errorMessage.empty())
{
VE_LOG("Successfully modified %s", result.assetInfo.m_relativePath.c_str());
VE_LOG("Successfully modified %s", result.asset.Path().c_str());
}
else
{
VE_LOG("Failed to modify %s: %s", result.assetInfo.m_relativePath.c_str(), result.errorMessage.data());
VE_LOG("Failed to modify %s: %s", result.asset.Path().c_str(), result.errorMessage.data());
}
for (auto* item : FindTableItems(info))
@ -288,12 +237,10 @@ namespace ScriptCanvasEditor
AddLogEntries();
}
void Controller::OnGraphUpgradeComplete(AZ::Data::Asset<AZ::Data::AssetData>& asset, bool skipped)
void Controller::OnGraphUpgradeComplete(ScriptCanvasEditor::SourceHandle& asset, bool skipped)
{
ModificationResult result;
result.asset = asset;
AZ::Data::AssetCatalogRequestBus::BroadcastResult
( result.assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, asset.GetId());
if (skipped)
{
@ -341,19 +288,19 @@ namespace ScriptCanvasEditor
}
}
void Controller::OnScanFilteredGraph(const AZ::Data::AssetInfo& info)
void Controller::OnScanFilteredGraph(const SourceHandle& info)
{
OnScannedGraph(info, Filtered::Yes);
}
void Controller::OnScannedGraph(const AZ::Data::AssetInfo& assetInfo, [[maybe_unused]] Filtered filtered)
void Controller::OnScannedGraph(const SourceHandle& assetInfo, [[maybe_unused]] Filtered filtered)
{
const int rowIndex = m_view->tableWidget->rowCount();
if (filtered == Filtered::No || !m_view->onlyShowOutdated->isChecked())
{
m_view->tableWidget->insertRow(rowIndex);
QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.m_relativePath.c_str()));
QTableWidgetItem* rowName = new QTableWidgetItem(tr(assetInfo.Path().c_str()));
m_view->tableWidget->setItem(rowIndex, static_cast<int>(ColumnAsset), rowName);
SetRowSucceeded(rowIndex);
@ -375,17 +322,11 @@ namespace ScriptCanvasEditor
m_view->tableWidget->setCellWidget(rowIndex, static_cast<int>(ColumnAction), upgradeButton);
}
char resolvedBuffer[AZ_MAX_PATH_LEN] = { 0 };
AZStd::string path = AZStd::string::format("@devroot@/%s", assetInfo.m_relativePath.c_str());
AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedBuffer, AZ_MAX_PATH_LEN);
AZ::StringFunc::Path::GetFullPath(resolvedBuffer, path);
AZ::StringFunc::Path::Normalize(path);
bool result = false;
AZ::Data::AssetInfo info;
AZStd::string watchFolder;
QByteArray assetNameUtf8 = assetInfo.m_relativePath.c_str();
QByteArray assetNameUtf8 = assetInfo.Path().c_str();
AzToolsFramework::AssetSystemRequestBus::BroadcastResult
( result
, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath
@ -412,41 +353,41 @@ namespace ScriptCanvasEditor
OnScannedGraphResult(assetInfo);
}
void Controller::OnScannedGraphResult([[maybe_unused]] const AZ::Data::AssetInfo& info)
void Controller::OnScannedGraphResult([[maybe_unused]] const SourceHandle& info)
{
m_view->progressBar->setValue(aznumeric_cast<int>(m_handledAssetCount));
++m_handledAssetCount;
AddLogEntries();
}
void Controller::OnScanLoadFailure(const AZ::Data::AssetInfo& info)
void Controller::OnScanLoadFailure(const SourceHandle& info)
{
const int rowIndex = m_view->tableWidget->rowCount();
m_view->tableWidget->insertRow(rowIndex);
QTableWidgetItem* rowName = new QTableWidgetItem
( tr(AZStd::string::format("Load Error: %s", info.m_relativePath.c_str()).c_str()));
( tr(AZStd::string::format("Load Error: %s", info.Path().c_str()).c_str()));
m_view->tableWidget->setItem(rowIndex, static_cast<int>(ColumnAsset), rowName);
SetRowFailed(rowIndex, "Load failed");
OnScannedGraphResult(info);
}
void Controller::OnScanUnFilteredGraph(const AZ::Data::AssetInfo& info)
void Controller::OnScanUnFilteredGraph(const SourceHandle& info)
{
OnScannedGraph(info, Filtered::No);
}
void Controller::OnUpgradeBegin
( const ModifyConfiguration& config
, [[maybe_unused]] const WorkingAssets& assets)
, [[maybe_unused]] const AZStd::vector<SourceHandle>& assets)
{
QString spinnerText = QStringLiteral("Upgrade in progress - ");
if (config.modifySingleAsset.m_assetId.IsValid())
if (!config.modifySingleAsset.Path().empty())
{
spinnerText.append(" single graph");
if (assets.size() == 1)
{
for (auto* item : FindTableItems(assets.front().info))
for (auto* item : FindTableItems(assets.front()))
{
int row = item->row();
SetRowBusy(row);
@ -497,7 +438,7 @@ namespace ScriptCanvasEditor
m_view->scanButton->setEnabled(true);
}
void Controller::OnUpgradeDependenciesGathered(const AZ::Data::AssetInfo& info, Result result)
void Controller::OnUpgradeDependenciesGathered(const SourceHandle& info, Result result)
{
for (auto* item : FindTableItems(info))
{
@ -526,7 +467,7 @@ namespace ScriptCanvasEditor
void Controller::OnUpgradeDependencySortBegin
( [[maybe_unused]] const ModifyConfiguration& config
, const WorkingAssets& assets)
, const AZStd::vector<SourceHandle>& assets)
{
m_handledAssetCount = 0;
m_view->progressBar->setVisible(true);
@ -552,7 +493,7 @@ namespace ScriptCanvasEditor
void Controller::OnUpgradeDependencySortEnd
( [[maybe_unused]] const ModifyConfiguration& config
, const WorkingAssets& assets
, const AZStd::vector<SourceHandle>& assets
, [[maybe_unused]] const AZStd::vector<size_t>& sortedOrder)
{
m_handledAssetCount = 0;

@ -15,6 +15,7 @@
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
#include <Editor/View/Windows/Tools/UpgradeTool/FileSaver.h>
#include <ScriptCanvas/Assets/ScriptCanvasAssetHandler.h>
#include <ScriptCanvas/Assets/ScriptCanvasFileHandling.h>
namespace ScriptCanvasEditor
{
@ -27,6 +28,11 @@ namespace ScriptCanvasEditor
, m_onComplete(onComplete)
{}
const SourceHandle& FileSaver::GetSource() const
{
return m_source;
}
void FileSaver::PerformMove
( AZStd::string tmpFileName
, AZStd::string target
@ -37,7 +43,7 @@ namespace ScriptCanvasEditor
AZ::SystemTickBus::QueueFunction([this, tmpFileName]()
{
FileSaveResult result;
result.fileSaveError = "Failed to move updated file from temporary location to tmpFileName destination";
result.fileSaveError = "Failed to move updated file from temporary location to original destination.";
result.tempFileRemovalError = RemoveTempFile(tmpFileName);
m_onComplete(result);
});
@ -65,7 +71,9 @@ namespace ScriptCanvasEditor
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str());
// Bump the slice asset up in the asset processor's queue.
AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str());
AzFramework::AssetSystemRequestBus::Broadcast
(&AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetBySearchTerm, target.c_str());
AZ::SystemTickBus::QueueFunction([this, tmpFileName]()
{
FileSaveResult result;
@ -75,28 +83,29 @@ namespace ScriptCanvasEditor
}
else
{
AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false, "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str());
AZ_Warning(ScriptCanvas::k_VersionExplorerWindow.data(), false
, "moving converted file to tmpFileName destination failed: %s, trying again", target.c_str());
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(target.c_str());
streamer->SetRequestCompleteCallback(flushRequest, [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request)
streamer->SetRequestCompleteCallback(flushRequest
, [this, tmpFileName, target, remainingAttempts]([[maybe_unused]] AZ::IO::FileRequestHandle request)
{
// Continue saving.
AZ::SystemTickBus::QueueFunction([this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); });
AZ::SystemTickBus::QueueFunction(
[this, tmpFileName, target, remainingAttempts]() { PerformMove(tmpFileName, target, remainingAttempts - 1); });
});
streamer->QueueRequest(flushRequest);
}
}
}
void FileSaver::OnSourceFileReleased(AZ::Data::Asset<AZ::Data::AssetData> asset)
void FileSaver::OnSourceFileReleased(const SourceHandle& source)
{
AZStd::string relativePath, fullPath;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId());
bool fullPathFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(fullPathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, relativePath, fullPath);
AZStd::string fullPath = source.Path().c_str();
AZStd::string tmpFileName;
// here we are saving the graph to a temp file instead of the original file and then copying the temp file to the original file.
// This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing. Temp files are ignored by AP.
// This ensures that AP will not a get a file change notification on an incomplete graph file causing it to fail processing.
// Temp files are ignored by AP.
if (!AZ::IO::CreateTempFileName(fullPath.c_str(), tmpFileName))
{
FileSaveResult result;
@ -105,23 +114,24 @@ namespace ScriptCanvasEditor
return;
}
bool tempSavedSucceeded = false;
AZStd::string saveError;
AZ::IO::FileIOStream fileStream(tmpFileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText);
if (fileStream.IsOpen())
{
if (asset.GetType() == azrtti_typeid<ScriptCanvasEditor::ScriptCanvasAsset>())
auto saveOutcome = ScriptCanvasEditor::SaveToStream(source, fileStream);
if (!saveOutcome.IsSuccess())
{
ScriptCanvasEditor::ScriptCanvasAssetHandler handler;
tempSavedSucceeded = handler.SaveAssetData(asset, &fileStream);
saveError = saveOutcome.TakeError();
}
fileStream.Close();
}
if (!tempSavedSucceeded)
if (!saveError.empty())
{
FileSaveResult result;
result.fileSaveError = "Save asset data to temporary file failed";
result.fileSaveError = AZStd::string::format("Save asset data to temporary file failed: %s", saveError.c_str());
m_onComplete(result);
return;
}
@ -131,26 +141,26 @@ namespace ScriptCanvasEditor
, fullPath.c_str()
, true
, [this, fullPath, tmpFileName]([[maybe_unused]] bool success, const AzToolsFramework::SourceControlFileInfo& info)
{
constexpr const size_t k_maxAttemps = 10;
{
constexpr const size_t k_maxAttemps = 10;
if (!info.IsReadOnly())
{
PerformMove(tmpFileName, fullPath, k_maxAttemps);
}
else if (m_onReadOnlyFile && m_onReadOnlyFile())
{
AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true);
PerformMove(tmpFileName, fullPath, k_maxAttemps);
}
else
{
FileSaveResult result;
result.fileSaveError = "Source file was and remained read-only";
result.tempFileRemovalError = RemoveTempFile(tmpFileName);
m_onComplete(result);
}
});
if (!info.IsReadOnly())
{
PerformMove(tmpFileName, fullPath, k_maxAttemps);
}
else if (m_onReadOnlyFile && m_onReadOnlyFile())
{
AZ::IO::SystemFile::SetWritable(info.m_filePath.c_str(), true);
PerformMove(tmpFileName, fullPath, k_maxAttemps);
}
else
{
FileSaveResult result;
result.fileSaveError = "Source file was and remained read-only";
result.tempFileRemovalError = RemoveTempFile(tmpFileName);
m_onComplete(result);
}
});
}
AZStd::string FileSaver::RemoveTempFile(AZStd::string_view tempFile)
@ -158,7 +168,7 @@ namespace ScriptCanvasEditor
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
if (!fileIO)
{
return "GraphUpgradeComplete: No FileIO instance";
return "No FileIO instance";
}
if (fileIO->Exists(tempFile.data()) && !fileIO->Remove(tempFile.data()))
@ -169,30 +179,30 @@ namespace ScriptCanvasEditor
return "";
}
void FileSaver::Save(AZ::Data::Asset<AZ::Data::AssetData> asset)
void FileSaver::Save(const SourceHandle& source)
{
AZStd::string relativePath, fullPath;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(relativePath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, asset.GetId());
bool fullPathFound = false;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult
(fullPathFound
, &AzToolsFramework::AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath
, relativePath, fullPath);
if (!fullPathFound)
m_source = source;
if (source.Path().empty())
{
FileSaveResult result;
result.fileSaveError = "Full source path not found";
result.fileSaveError = "No save location specified";
m_onComplete(result);
}
else
{
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(fullPath);
streamer->SetRequestCompleteCallback(flushRequest, [this, asset]([[maybe_unused]] AZ::IO::FileRequestHandle request)
AZ::IO::FileRequestPtr flushRequest = streamer->FlushCache(source.Path().c_str());
streamer->SetRequestCompleteCallback(flushRequest, [this]([[maybe_unused]] AZ::IO::FileRequestHandle request)
{
this->OnSourceFileReleased(asset);
AZStd::lock_guard<AZStd::mutex> lock(m_mutex);
if (!m_sourceFileReleased)
{
m_sourceFileReleased = true;
AZ::SystemTickBus::QueueFunction([this]() { this->OnSourceFileReleased(m_source); });
}
});
streamer->QueueRequest(flushRequest);
}
}

@ -51,6 +51,7 @@ namespace GraphCpp
VariablePanelSymantics,
AddVersionData,
RemoveFunctionGraphMarker,
FixupVersionDataTypeId,
// label your version above
Current
};
@ -70,9 +71,17 @@ namespace ScriptCanvas
componentElementNode.AddElementWithData(context, "m_assetType", azrtti_typeid<RuntimeAsset>());
}
if (componentElementNode.GetVersion() < GraphCpp::GraphVersion::RemoveFunctionGraphMarker)
if (auto subElement = componentElementNode.FindElement(AZ_CRC_CE("isFunctionGraph")); subElement > 0)
{
componentElementNode.RemoveElementByName(AZ_CRC_CE("isFunctionGraph"));
componentElementNode.RemoveElement(subElement);
}
if (auto subElement = componentElementNode.FindSubElement(AZ_CRC_CE("versionData")))
{
if (subElement->GetId() == azrtti_typeid<SlotId>())
{
componentElementNode.RemoveElementByName(AZ_CRC_CE("versionData"));
}
}
return true;
@ -1189,11 +1198,6 @@ namespace ScriptCanvas
m_isObserved = isObserved;
}
AZ::Data::AssetType Graph::GetAssetType() const
{
return m_assetType;
}
void Graph::VersioningRemoveSlot(ScriptCanvas::Node& scriptCanvasNode, const SlotId& slotId)
{
bool deletedSlot = true;

Loading…
Cancel
Save