diff --git a/Assets/Engine/Engine_Dependencies.xml b/Assets/Engine/Engine_Dependencies.xml
index 0d6541e18e..b969b3bc97 100644
--- a/Assets/Engine/Engine_Dependencies.xml
+++ b/Assets/Engine/Engine_Dependencies.xml
@@ -1,16 +1,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed
index aafbffbe8f..18ccd19dc3 100644
--- a/Assets/Engine/SeedAssetList.seed
+++ b/Assets/Engine/SeedAssetList.seed
@@ -1,621 +1,260 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/AutomatedTesting/Editor/Scripts/Profiler/__init__.py b/AutomatedTesting/Editor/Scripts/Profiler/__init__.py
new file mode 100644
index 0000000000..7a325ca97e
--- /dev/null
+++ b/AutomatedTesting/Editor/Scripts/Profiler/__init__.py
@@ -0,0 +1,7 @@
+#
+# 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
+#
+#
diff --git a/AutomatedTesting/Editor/Scripts/Profiler/profiler_system_example.py b/AutomatedTesting/Editor/Scripts/Profiler/profiler_system_example.py
new file mode 100644
index 0000000000..16f161c50e
--- /dev/null
+++ b/AutomatedTesting/Editor/Scripts/Profiler/profiler_system_example.py
@@ -0,0 +1,30 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+import azlmbr.debug as debug
+
+import pathlib
+
+def test_profiler_system():
+ if not debug.g_ProfilerSystem.IsValid():
+ print('g_ProfilerSystem is INVALID')
+ return
+
+ state = 'ACTIVE' if debug.g_ProfilerSystem.IsActive() else 'INACTIVE'
+ print(f'Profiler system is currently {state}')
+
+ capture_location = pathlib.Path(debug.g_ProfilerSystem.GetCaptureLocation())
+ print(f'Capture location set to {capture_location}')
+
+ print('Capturing single frame...' )
+ capture_file = str(capture_location / 'script_capture_frame.json')
+ debug.g_ProfilerSystem.CaptureFrame(capture_file)
+
+# Invoke main function
+if __name__ == '__main__':
+ test_profiler_system()
diff --git a/AutomatedTesting/Gem/Code/CMakeLists.txt b/AutomatedTesting/Gem/Code/CMakeLists.txt
index 6f55cc2764..8808507765 100644
--- a/AutomatedTesting/Gem/Code/CMakeLists.txt
+++ b/AutomatedTesting/Gem/Code/CMakeLists.txt
@@ -14,15 +14,25 @@ ly_add_target(
FILES_CMAKE
automatedtesting_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
+ automatedtesting_autogen_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
+ PUBLIC
+ AZ::AzNetworking
+ Gem::Multiplayer
PRIVATE
AZ::AzCore
Gem::Atom_AtomBridge.Static
+ Gem::Multiplayer.Static
+ AUTOGEN_RULES
+ *.AutoComponent.xml,AutoComponent_Header.jinja,$path/$fileprefix.AutoComponent.h
+ *.AutoComponent.xml,AutoComponent_Source.jinja,$path/$fileprefix.AutoComponent.cpp
+ *.AutoComponent.xml,AutoComponentTypes_Header.jinja,$path/AutoComponentTypes.h
+ *.AutoComponent.xml,AutoComponentTypes_Source.jinja,$path/AutoComponentTypes.cpp
)
# if enabled, AutomatedTesting is used by all kinds of applications
diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml
new file mode 100644
index 0000000000..12c222add6
--- /dev/null
+++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/AutomatedTesting/Gem/Code/Source/AutomatedTestingModule.cpp b/AutomatedTesting/Gem/Code/Source/AutomatedTestingModule.cpp
index 7ed37e89ca..b5be8410ef 100644
--- a/AutomatedTesting/Gem/Code/Source/AutomatedTestingModule.cpp
+++ b/AutomatedTesting/Gem/Code/Source/AutomatedTestingModule.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
@@ -27,6 +28,8 @@ namespace AutomatedTesting
m_descriptors.insert(m_descriptors.end(), {
AutomatedTestingSystemComponent::CreateDescriptor(),
});
+
+ CreateComponentDescriptors(m_descriptors); //< Register multiplayer components
}
/**
diff --git a/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp b/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp
index 3b373b1f65..06a0775d70 100644
--- a/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp
+++ b/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
@@ -45,7 +46,7 @@ namespace AutomatedTesting
void AutomatedTestingSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
- AZ_UNUSED(required);
+ required.push_back(AZ_CRC_CE("MultiplayerService"));
}
void AutomatedTestingSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
@@ -60,6 +61,7 @@ namespace AutomatedTesting
void AutomatedTestingSystemComponent::Activate()
{
AutomatedTestingRequestBus::Handler::BusConnect();
+ RegisterMultiplayerComponents(); //< Register AutomatedTesting's multiplayer components to assign NetComponentIds
}
void AutomatedTestingSystemComponent::Deactivate()
diff --git a/AutomatedTesting/Gem/Code/automatedtesting_autogen_files.cmake b/AutomatedTesting/Gem/Code/automatedtesting_autogen_files.cmake
new file mode 100644
index 0000000000..b3c6fcaa0b
--- /dev/null
+++ b/AutomatedTesting/Gem/Code/automatedtesting_autogen_files.cmake
@@ -0,0 +1,14 @@
+#
+# 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
+#
+#
+
+set(FILES
+ ${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Common.jinja
+ ${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Header.jinja
+ ${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja
+ ${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponentTypes_Header.jinja
+ ${LY_ROOT_FOLDER}/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponentTypes_Source.jinja
+)
diff --git a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake
index 6bf2bf72d9..eb619104a4 100644
--- a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake
+++ b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake
@@ -11,4 +11,5 @@ set(FILES
Source/AutomatedTestingModule.cpp
Source/AutomatedTestingSystemComponent.cpp
Source/AutomatedTestingSystemComponent.h
+ Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml
)
diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake
index f653a54505..e6a4d6ca37 100644
--- a/AutomatedTesting/Gem/Code/enabled_gems.cmake
+++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake
@@ -55,4 +55,5 @@ set(ENABLED_GEMS
PrefabBuilder
AudioSystem
Profiler
+ Multiplayer
)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
index 23fb249761..f0e92c7e3e 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
@@ -13,10 +13,10 @@ import zipfile
import pytest
import ly_test_tools.environment.file_system as file_system
-from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator
import editor_python_test_tools.hydra_test_utils as hydra
+from .atom_utils.atom_component_helper import compare_screenshot_similarity, ImageComparisonTestFailure
logger = logging.getLogger(__name__)
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
@@ -69,7 +69,7 @@ def create_screenshots_archive(screenshot_path):
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ["windows_editor"])
-@pytest.mark.parametrize("level", ["auto_test"])
+@pytest.mark.parametrize("level", ["Base"])
class TestAllComponentsIndepthTests(object):
@pytest.mark.parametrize("screenshot_name", ["AtomBasicLevelSetup.ppm"])
@@ -91,12 +91,7 @@ class TestAllComponentsIndepthTests(object):
"Viewport is set to the expected size: True",
"Exited game mode"
]
- unexpected_lines = [
- "Trace::Assert",
- "Trace::Error",
- "Traceback (most recent call last):",
- "Screenshot failed"
- ]
+ unexpected_lines = ["Traceback (most recent call last):"]
hydra.launch_and_validate_results(
request,
@@ -111,10 +106,12 @@ class TestAllComponentsIndepthTests(object):
null_renderer=False,
)
- for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
- compare_screenshots(test_screenshot, golden_screenshot)
-
- create_screenshots_archive(screenshot_directory)
+ similarity_threshold = 0.99
+ for test_screenshot, golden_image in zip(test_screenshots, golden_images):
+ screenshot_comparison_result = compare_screenshot_similarity(
+ test_screenshot, golden_image, similarity_threshold, True, screenshot_directory)
+ if screenshot_comparison_result != "Screenshots match":
+ raise Exception(f"Screenshot test failed: {screenshot_comparison_result}")
@pytest.mark.test_case_id("C34525095")
def test_LightComponent_ScreenshotMatchesGoldenImage(
@@ -149,12 +146,7 @@ class TestAllComponentsIndepthTests(object):
golden_images.append(golden_image_path)
expected_lines = ["spot_light Controller|Configuration|Shadows|Shadowmap size: SUCCESS"]
- unexpected_lines = [
- "Trace::Assert",
- "Trace::Error",
- "Traceback (most recent call last):",
- "Screenshot failed",
- ]
+ unexpected_lines = ["Traceback (most recent call last):"]
hydra.launch_and_validate_results(
request,
TEST_DIRECTORY,
@@ -168,10 +160,12 @@ class TestAllComponentsIndepthTests(object):
null_renderer=False,
)
- for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
- compare_screenshots(test_screenshot, golden_screenshot)
-
- create_screenshots_archive(screenshot_directory)
+ similarity_threshold = 0.99
+ for test_screenshot, golden_image in zip(test_screenshots, golden_images):
+ screenshot_comparison_result = compare_screenshot_similarity(
+ test_screenshot, golden_image, similarity_threshold, True, screenshot_directory)
+ if screenshot_comparison_result != "Screenshots match":
+ raise ImageComparisonTestFailure(f"Screenshot test failed: {screenshot_comparison_result}")
@pytest.mark.parametrize('rhi', ['dx12', 'vulkan'])
@@ -219,7 +213,6 @@ class TestPerformanceBenchmarkSuite(object):
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
-@pytest.mark.system
class TestMaterialEditor(object):
@pytest.mark.parametrize("cfg_args,expected_lines", [
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
index 45298ed563..950bd44199 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
@@ -42,6 +42,10 @@ class TestAutomation(EditorTestSuite):
class AtomEditorComponents_GridAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module
+ @pytest.mark.test_case_id("C36525671")
+ class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module
+
@pytest.mark.test_case_id("C32078117")
class AtomEditorComponents_LightAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
@@ -54,6 +58,10 @@ class TestAutomation(EditorTestSuite):
class AtomEditorComponents_MeshAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
+ @pytest.mark.test_case_id("C36525663")
+ class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module
+
@pytest.mark.test_case_id("C32078125")
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
index 11832f8846..50cc15f7e8 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
@@ -1,5 +1,6 @@
"""
-Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
+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
@@ -8,12 +9,19 @@ import datetime
import os
import zipfile
+from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
+
+
+class ImageComparisonTestFailure(Exception):
+ """Custom test failure for failed image comparisons."""
+ pass
+
def create_screenshots_archive(screenshot_path):
"""
Creates a new zip file archive at archive_path containing all files listed within archive_path.
:param screenshot_path: location containing the files to archive, the zip archive file will also be saved here.
- :return: None, but creates a new zip file archive inside path containing all of the files inside archive_path.
+ :return: path to the created .zip file archive.
"""
files_to_archive = []
@@ -27,14 +35,16 @@ def create_screenshots_archive(screenshot_path):
# Setup variables for naming the zip archive file.
timestamp = datetime.datetime.now().timestamp()
formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S")
- screenshots_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip')
+ screenshots_zip_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip')
# Write all of the valid .png and .ppm files to the archive file.
- with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
+ with zipfile.ZipFile(screenshots_zip_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
for file_path in files_to_archive:
file_name = os.path.basename(file_path)
zip_archive.write(file_path, file_name)
+ return screenshots_zip_file
+
def golden_images_directory():
"""
@@ -53,6 +63,36 @@ def golden_images_directory():
return golden_images_dir
+def compare_screenshot_similarity(
+ test_screenshot, golden_image, similarity_threshold, create_zip_archive=False, screenshot_directory=""):
+ """
+ Compares the similarity between a test screenshot and a golden image.
+ It returns a "Screenshots match" string if the comparison mean value is higher than the similarity threshold.
+ Otherwise, it returns an error string.
+ :param test_screenshot: path to the test screenshot to compare.
+ :param golden_image: path to the golden image to compare.
+ :param similarity_threshold: value for the comparison mean value to be asserted against.
+ :param create_zip_archive: toggle to create a zip archive containing the screenshots if the assert check fails.
+ :param screenshot_directory: directory containing screenshots to create zip archive from.
+ :return: Error string if compared mean value < similarity threshold or screenshot_directory is missing for .zip,
+ otherwise it returns a "Screenshots match" string.
+ """
+ result = "Screenshots match"
+ if create_zip_archive and not screenshot_directory:
+ result = 'You must specify a screenshot_directory in order to create a zip archive.\n'
+
+ mean_similarity = compare_screenshots(test_screenshot, golden_image)
+ if not mean_similarity > similarity_threshold:
+ if create_zip_archive:
+ create_screenshots_archive(screenshot_directory)
+ result = (
+ f"When comparing the test_screenshot: '{test_screenshot}' "
+ f"to golden_image: '{golden_image}' the mean similarity of '{mean_similarity}' "
+ f"was lower than the similarity threshold of '{similarity_threshold}'. ")
+
+ return result
+
+
def create_basic_atom_level(level_name):
"""
Creates a new level inside the Editor matching level_name & adds the following:
@@ -76,29 +116,11 @@ def create_basic_atom_level(level_name):
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
- # Create a new level.
- new_level_name = level_name
- heightmap_resolution = 512
- heightmap_meters_per_pixel = 1
- terrain_texture_resolution = 412
- use_terrain = False
-
- # Return codes are ECreateLevelResult defined in CryEdit.h
- return_code = general.create_level_no_prompt(
- new_level_name, heightmap_resolution, heightmap_meters_per_pixel, terrain_texture_resolution, use_terrain)
- if return_code == 1:
- general.log(f"{new_level_name} level already exists")
- elif return_code == 2:
- general.log("Failed to create directory")
- elif return_code == 3:
- general.log("Directory length is too long")
- elif return_code != 0:
- general.log("Unknown error, failed to create level")
- else:
- general.log(f"{new_level_name} level created successfully")
-
- # Enable idle and update viewport.
+ # 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")
general.idle_wait(1.0)
general.update_viewport()
general.idle_wait(0.5) # half a second is more than enough for updating the viewport.
@@ -165,24 +187,25 @@ def create_basic_atom_level(level_name):
components=["Material"],
parent_id=default_level.id)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0)
- ground_plane_material_asset_path = os.path.join(
- "Materials", "Presets", "PBR", "metal_chrome.azmaterial")
- ground_plane_material_asset_value = 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_value)
- # Work around to add the correct Atom Mesh component
+ # 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("Models", "plane.azmodel")
+ ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel")
ground_plane_mesh_asset_value = asset.AssetCatalogRequestBus(
bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False)
ground_plane.get_set_test(1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset_value)
+ # Add Atom Material component and asset.
+ ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial")
+ ground_plane_material_asset_value = 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_value)
+
# Create directional_light entity and set the properties
directional_light = hydra.Entity("directional_light")
directional_light.create_entity(
@@ -199,12 +222,8 @@ def create_basic_atom_level(level_name):
entity_position=math.Vector3(0.0, 0.0, 1.0),
components=["Material"],
parent_id=default_level.id)
- sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial")
- sphere_material_asset_value = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False)
- sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value)
- # Work around to add the correct Atom Mesh component
+ # Work around to add the correct Atom Mesh component and asset.
sphere_entity.components.append(
editor.EditorComponentAPIBus(
bus.Broadcast, "AddComponentsOfType", sphere_entity.id, [mesh_type_id]
@@ -215,6 +234,12 @@ def create_basic_atom_level(level_name):
bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False)
sphere_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset_value)
+ # Add Atom Material component and asset.
+ sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial")
+ sphere_material_asset_value = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False)
+ sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value)
+
# Create camera component and set the properties
camera_entity = hydra.Entity("camera")
camera_entity.create_entity(
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
index 344a0dbd29..c365999335 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
@@ -218,6 +218,7 @@ class AtomComponentProperties:
properties = {
'name': 'HDR Color Grading',
'requires': [AtomComponentProperties.postfx_layer()],
+ 'Enable HDR color grading': 'Controller|Configuration|Enable HDR color grading',
}
return properties[property]
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py
new file mode 100644
index 0000000000..4972079fcd
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py
@@ -0,0 +1,192 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+
+class Tests:
+ creation_undo = (
+ "UNDO Entity creation success",
+ "UNDO Entity creation failed")
+ creation_redo = (
+ "REDO Entity creation success",
+ "REDO Entity creation failed")
+ hdr_color_grading_creation = (
+ "HDR Color Grading Entity successfully created",
+ "HDR Color Grading Entity failed to be created")
+ hdr_color_grading_component = (
+ "Entity has an HDR Color Grading component",
+ "Entity failed to find HDR Color Grading component")
+ hdr_color_grading_disabled = (
+ "HDR Color Grading component disabled",
+ "HDR Color Grading component was not disabled")
+ postfx_layer_component = (
+ "Entity has a PostFX Layer component",
+ "Entity did not have an PostFX Layer component")
+ hdr_color_grading_enabled = (
+ "HDR Color Grading component enabled",
+ "HDR Color Grading component was not enabled")
+ enable_hdr_color_grading_parameter_enabled = (
+ "Enable HDR Color Grading parameter enabled",
+ "Enable HDR Color Grading parameter was not enabled")
+ enter_game_mode = (
+ "Entered game mode",
+ "Failed to enter game mode")
+ exit_game_mode = (
+ "Exited game mode",
+ "Couldn't exit game mode")
+ is_visible = (
+ "Entity is visible",
+ "Entity was not visible")
+ is_hidden = (
+ "Entity is hidden",
+ "Entity was not hidden")
+ entity_deleted = (
+ "Entity deleted",
+ "Entity was not deleted")
+ deletion_undo = (
+ "UNDO deletion success",
+ "UNDO deletion failed")
+ deletion_redo = (
+ "REDO deletion success",
+ "REDO deletion failed")
+
+
+def AtomEditorComponents_HDRColorGrading_AddedToEntity():
+ """
+ Summary:
+ Tests the HDR Color Grading component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create an HDR Color Grading entity with no components.
+ 2) Add HDR Color Grading component to HDR Color Grading entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Verify HDR Color Grading component not enabled.
+ 6) Add PostFX Layer component since it is required by the HDR Color Grading component.
+ 7) Verify HDR Color Grading component is enabled.
+ 8) Enable the "Enable HDR Color Grading" parameter.
+ 9) Enter/Exit game mode.
+ 10) Test IsHidden.
+ 11) Test IsVisible.
+ 12) Delete HDR Color Grading entity.
+ 13) UNDO deletion.
+ 14) REDO deletion.
+ 15) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper
+ from Atom.atom_utils.atom_constants import AtomComponentProperties
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ TestHelper.init_idle()
+ TestHelper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create an HDR Color Grading entity with no components.
+ hdr_color_grading_entity = EditorEntity.create_editor_entity(AtomComponentProperties.hdr_color_grading())
+ Report.critical_result(Tests.hdr_color_grading_creation, hdr_color_grading_entity.exists())
+
+ # 2. Add HDR Color Grading component to HDR Color Grading entity.
+ hdr_color_grading_component = hdr_color_grading_entity.add_component(
+ AtomComponentProperties.hdr_color_grading())
+ Report.critical_result(
+ Tests.hdr_color_grading_component,
+ hdr_color_grading_entity.has_component(AtomComponentProperties.hdr_color_grading()))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not hdr_color_grading_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, hdr_color_grading_entity.exists())
+
+ # 5. Verify HDR Color Grading component not enabled.
+ Report.result(Tests.hdr_color_grading_disabled, not hdr_color_grading_component.is_enabled())
+
+ # 6. Add PostFX Layer component since it is required by the HDR Color Grading component.
+ hdr_color_grading_entity.add_component(AtomComponentProperties.postfx_layer())
+ Report.result(
+ Tests.postfx_layer_component,
+ hdr_color_grading_entity.has_component(AtomComponentProperties.postfx_layer()))
+
+ # 7. Verify HDR Color Grading component is enabled.
+ Report.result(Tests.hdr_color_grading_enabled, hdr_color_grading_component.is_enabled())
+
+ # 8. Enable the "Enable HDR Color Grading" parameter.
+ hdr_color_grading_component.set_component_property_value(
+ AtomComponentProperties.hdr_color_grading('Enable HDR color grading'), True)
+ Report.result(Tests.enable_hdr_color_grading_parameter_enabled,
+ hdr_color_grading_component.get_component_property_value(
+ AtomComponentProperties.hdr_color_grading('Enable HDR color grading')) is True)
+
+ # 9. Enter/Exit game mode.
+ TestHelper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ TestHelper.exit_game_mode(Tests.exit_game_mode)
+
+ # 10. Test IsHidden.
+ hdr_color_grading_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, hdr_color_grading_entity.is_hidden() is True)
+
+ # 11. Test IsVisible.
+ hdr_color_grading_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, hdr_color_grading_entity.is_visible() is True)
+
+ # 12. Delete HDR Color Grading entity.
+ hdr_color_grading_entity.delete()
+ Report.result(Tests.entity_deleted, not hdr_color_grading_entity.exists())
+
+ # 13. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, hdr_color_grading_entity.exists())
+
+ # 14. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not hdr_color_grading_entity.exists())
+
+ # 15. Look for errors and asserts.
+ TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
+ for error_info in error_tracer.errors:
+ Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
+ for assert_info in error_tracer.asserts:
+ Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_HDRColorGrading_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py
new file mode 100644
index 0000000000..4226ae3dfe
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py
@@ -0,0 +1,159 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+
+class Tests:
+ creation_undo = (
+ "UNDO Entity creation success",
+ "UNDO Entity creation failed")
+ creation_redo = (
+ "REDO Entity creation success",
+ "REDO Entity creation failed")
+ occlusion_culling_plane_entity_creation = (
+ "Occlusion Culling Plane Entity successfully created",
+ "Occlusion Culling Plane Entity failed to be created")
+ occlusion_culling_plane_component_added = (
+ "Entity has a Occlusion Culling Plane component",
+ "Entity failed to find Occlusion Culling Plane component")
+ enter_game_mode = (
+ "Entered game mode",
+ "Failed to enter game mode")
+ exit_game_mode = (
+ "Exited game mode",
+ "Couldn't exit game mode")
+ is_visible = (
+ "Entity is visible",
+ "Entity was not visible")
+ is_hidden = (
+ "Entity is hidden",
+ "Entity was not hidden")
+ entity_deleted = (
+ "Entity deleted",
+ "Entity was not deleted")
+ deletion_undo = (
+ "UNDO deletion success",
+ "UNDO deletion failed")
+ deletion_redo = (
+ "REDO deletion success",
+ "REDO deletion failed")
+
+
+def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity():
+ """
+ Summary:
+ Tests the occlusion culling plane component can be added to an entity and has the expected functionality.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
+ Creation and deletion undo/redo should also work.
+
+ Test Steps:
+ 1) Create a Occlusion Culling Plane entity with no components.
+ 2) Add a Occlusion Culling Plane component to Occlusion Culling Plane entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Enter/Exit game mode.
+ 6) Test IsHidden.
+ 7) Test IsVisible.
+ 8) Delete Occlusion Culling Plane entity.
+ 9) UNDO deletion.
+ 10) REDO deletion.
+ 11) Look for errors.
+
+ :return: None
+ """
+
+ import azlmbr.legacy.general as general
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper
+ from Atom.atom_utils.atom_constants import AtomComponentProperties
+
+ with Tracer() as error_tracer:
+ # Test setup begins.
+ # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
+ TestHelper.init_idle()
+ TestHelper.open_level("", "Base")
+
+ # Test steps begin.
+ # 1. Create a occlusion culling plane entity with no components.
+ occlusion_culling_plane_entity = EditorEntity.create_editor_entity(
+ AtomComponentProperties.occlusion_culling_plane())
+ Report.critical_result(Tests.occlusion_culling_plane_entity_creation,
+ occlusion_culling_plane_entity.exists())
+
+ # 2. Add a occlusion culling plane component to occlusion culling plane entity.
+ occlusion_culling_plane_component = occlusion_culling_plane_entity.add_component(
+ AtomComponentProperties.occlusion_culling_plane())
+ Report.critical_result(
+ Tests.occlusion_culling_plane_component_added,
+ occlusion_culling_plane_entity.has_component(AtomComponentProperties.occlusion_culling_plane()))
+
+ # 3. UNDO the entity creation and component addition.
+ # -> UNDO component addition.
+ general.undo()
+ # -> UNDO naming entity.
+ general.undo()
+ # -> UNDO selecting entity.
+ general.undo()
+ # -> UNDO entity creation.
+ general.undo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_undo, not occlusion_culling_plane_entity.exists())
+
+ # 4. REDO the entity creation and component addition.
+ # -> REDO entity creation.
+ general.redo()
+ # -> REDO selecting entity.
+ general.redo()
+ # -> REDO naming entity.
+ general.redo()
+ # -> REDO component addition.
+ general.redo()
+ general.idle_wait_frames(1)
+ Report.result(Tests.creation_redo, occlusion_culling_plane_entity.exists())
+
+ # 5. Enter/Exit game mode.
+ TestHelper.enter_game_mode(Tests.enter_game_mode)
+ general.idle_wait_frames(1)
+ TestHelper.exit_game_mode(Tests.exit_game_mode)
+
+ # 6. Test IsHidden.
+ occlusion_culling_plane_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, occlusion_culling_plane_entity.is_hidden() is True)
+
+ # 7. Test IsVisible.
+ occlusion_culling_plane_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, occlusion_culling_plane_entity.is_visible() is True)
+
+ # 8. Delete occlusion_culling_plane entity.
+ occlusion_culling_plane_entity.delete()
+ Report.result(Tests.entity_deleted, not occlusion_culling_plane_entity.exists())
+
+ # 9. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, occlusion_culling_plane_entity.exists())
+
+ # 10. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not occlusion_culling_plane_entity.exists())
+
+ # 11. Look for errors or asserts.
+ TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
+ for error_info in error_tracer.errors:
+ Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
+ for assert_info in error_tracer.asserts:
+ Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomEditorComponents_OcclusionCullingPlane_AddedToEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py
index a81864f379..efef4c0a43 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py
@@ -70,8 +70,6 @@ def AtomEditorComponents_postfx_layer_AddedToEntity():
:return: None
"""
- import os
-
import azlmbr.legacy.general as general
from editor_python_test_tools.editor_entity_utils import EditorEntity
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
index 9515712583..645447e6de 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
@@ -6,18 +6,6 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
-import sys
-
-import azlmbr.asset as asset
-import azlmbr.bus as bus
-import azlmbr.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
-
-sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper
@@ -45,9 +33,18 @@ def run():
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, & saves the level.
+ 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()
@@ -84,33 +81,11 @@ def run():
general.run_console("r_displayInfo=0")
general.idle_wait(1.0)
- return True
-
# Wait for Editor idle loop before executing Python hydra scripts.
general.idle_enable(True)
- # Open the auto_test level.
- new_level_name = "auto_test" # Specified in class TestAllComponentsIndepthTests()
- heightmap_resolution = 512
- heightmap_meters_per_pixel = 1
- terrain_texture_resolution = 412
- use_terrain = False
-
- # Return codes are ECreateLevelResult defined in CryEdit.h
- return_code = general.create_level_no_prompt(
- new_level_name, heightmap_resolution, heightmap_meters_per_pixel, terrain_texture_resolution, use_terrain)
- if return_code == 1:
- general.log(f"{new_level_name} level already exists")
- elif return_code == 2:
- general.log("Failed to create directory")
- elif return_code == 3:
- general.log("Directory length is too long")
- elif return_code != 0:
- general.log("Unknown error, failed to create level")
- else:
- general.log(f"{new_level_name} level created successfully")
-
- # Basic setup for newly created level.
+ # Basic setup for opened level.
+ helper.open_level(level_name="Base")
after_level_load()
initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT)
@@ -147,22 +122,25 @@ def run():
parent_id=default_level.id
)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0)
- 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)
- # Work around to add the correct Atom Mesh component
+
+ # 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("Objects", "plane.azmodel")
+ 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(
@@ -180,11 +158,8 @@ def run():
components=["Material"],
parent_id=default_level.id
)
- 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)
- # Work around to add the correct Atom Mesh component
+
+ # Work around to add the correct Atom Mesh component and asset.
sphere.components.append(
editor.EditorComponentAPIBus(
bus.Broadcast, "AddComponentsOfType", sphere.id, [mesh_type_id]
@@ -195,6 +170,12 @@ def run():
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)
@@ -204,10 +185,9 @@ def run():
)
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation)
camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0)
- azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
+ camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
- # Save level, enter game mode, take screenshot, & exit game mode.
- general.save_level()
+ # Enter game mode, take screenshot, & exit game mode.
general.idle_wait(0.5)
general.enter_game_mode()
general.idle_wait(1.0)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
index 1c3e6226c1..f69ceb2120 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
@@ -22,7 +22,7 @@ from editor_python_test_tools.editor_test_helper import EditorTestHelper
helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
-LEVEL_NAME = "auto_test"
+LEVEL_NAME = "Base"
LIGHT_COMPONENT = "Light"
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
DEGREE_RADIAN_FACTOR = 0.0174533
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt
index cb83fe5344..aea2562e0b 100644
--- a/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt
@@ -6,7 +6,11 @@
#
#
-if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
+ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
+
+include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_BLAST Traits
+
+if(PAL_TRAIT_BLAST_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::BlastTests_Main
TEST_SUITE main
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake
new file mode 100644
index 0000000000..28767237de
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED TRUE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
index fd3222ba83..bec49185bd 100644
--- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
@@ -59,5 +59,8 @@ add_subdirectory(smoke)
## AWS ##
add_subdirectory(AWS)
+## Multiplayer ##
+add_subdirectory(Multiplayer)
+
## Integration tests for editor testing framework ##
add_subdirectory(editor_test_testing)
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
index 844f8de903..9e857ed8bc 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
@@ -107,6 +107,19 @@ class EditorComponent:
return type_ids
+
+def convert_to_azvector3(xyz) -> azlmbr.math.Vector3:
+ """
+ Converts a vector3-like element into a azlmbr.math.Vector3
+ """
+ if isinstance(xyz, Tuple) or isinstance(xyz, List):
+ assert len(xyz) == 3, ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
+ return math.Vector3(float(xyz[0]), float(xyz[1]), float(xyz[2]))
+ elif isinstance(xyz, type(math.Vector3())):
+ return xyz
+ else:
+ raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
+
class EditorEntity:
"""
Entity class is used to create and interact with Editor Entities.
@@ -183,15 +196,6 @@ class EditorEntity:
:return: EditorEntity class object
"""
- def convert_to_azvector3(xyz) -> math.Vector3:
- if isinstance(xyz, Tuple) or isinstance(xyz, List):
- assert len(xyz) == 3, ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
- return math.Vector3(*xyz)
- elif isinstance(xyz, type(math.Vector3())):
- return xyz
- else:
- raise ValueError("vector must be a 3 element list/tuple or azlmbr.math.Vector3")
-
if parent_id is None:
parent_id = azlmbr.entity.EntityId()
@@ -206,7 +210,7 @@ class EditorEntity:
return entity
# Methods
- def set_name(self, entity_name: str):
+ def set_name(self, entity_name: str) -> None:
"""
Given entity_name, sets name to Entity
:param: entity_name: Name of the entity to set
@@ -324,7 +328,7 @@ class EditorEntity:
self.start_status = status
return status
- def set_start_status(self, desired_start_status: str):
+ def set_start_status(self, desired_start_status: str) -> None:
"""
Set an entity as active/inactive at beginning of runtime or it is editor-only,
given its entity id and the start status then return set success
@@ -382,18 +386,75 @@ class EditorEntity:
"""
return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id)
+ # World Transform Functions
+ def get_world_translation(self) -> azlmbr.math.Vector3:
+ """
+ Gets the world translation of the entity
+ """
+ return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
+
+ def set_world_translation(self, new_translation) -> None:
+ """
+ Sets the new world translation of the current entity
+ """
+ new_translation = convert_to_azvector3(new_translation)
+ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetWorldTranslation", self.id, new_translation)
+
+ def get_world_rotation(self) -> azlmbr.math.Quaternion:
+ """
+ Gets the world rotation of the entity
+ """
+ return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldRotation", self.id)
+
+ def set_world_rotation(self, new_rotation):
+ """
+ Sets the new world rotation of the current entity
+ """
+ new_rotation = convert_to_azvector3(new_rotation)
+ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetWorldRotation", self.id, new_rotation)
+
+ # Local Transform Functions
+ def get_local_uniform_scale(self) -> float:
+ """
+ Gets the local uniform scale of the entity
+ """
+ return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalUniformScale", self.id)
+
def set_local_uniform_scale(self, scale_float) -> None:
"""
- Sets the "SetLocalUniformScale" value on the entity.
+ Sets the local uniform scale value(relative to the parent) on the entity.
:param scale_float: value for "SetLocalUniformScale" to set to.
:return: None
"""
azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", self.id, scale_float)
- def set_local_rotation(self, vector3_rotation) -> None:
+ def get_local_rotation(self) -> azlmbr.math.Quaternion:
"""
- Sets the "SetLocalRotation" value on the entity.
+ Gets the local rotation of the entity
+ """
+ return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalRotation", self.id)
+
+ def set_local_rotation(self, new_rotation) -> None:
+ """
+ Sets the set the local rotation(relative to the parent) of the current entity.
:param vector3_rotation: The math.Vector3 value to use for rotation on the entity (uses radians).
:return: None
"""
- azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, vector3_rotation)
+ new_rotation = convert_to_azvector3(new_rotation)
+ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, new_rotation)
+
+ def get_local_translation(self) -> azlmbr.math.Vector3:
+ """
+ Gets the local translation of the current entity.
+ :return: The math.Vector3 value of the local translation.
+ """
+ return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetLocalTranslation", self.id)
+
+ def set_local_translation(self, new_translation) -> None:
+ """
+ Sets the local translation(relative to the parent) of the current entity.
+ :param vector3_translation: The math.Vector3 value to use for translation on the entity.
+ :return: None
+ """
+ new_translation = convert_to_azvector3(new_translation)
+ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalTranslation", self.id, new_translation)
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py
index 10a6ab1ef4..76c2a42c0a 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py
@@ -138,6 +138,14 @@ class PrefabInstance:
self.container_entity = reparented_container_entity
current_instance_prefab.instances.add(self)
+ def get_direct_child_entities(self):
+ """
+ Returns the entities only contained in the current prefab instance.
+ This function does not return entities contained in other child instances
+ """
+ return self.container_entity.get_children()
+
+
# This is a helper class which contains some of the useful information about a prefab template.
class Prefab:
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
index 1b094b1cfa..481d73274f 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
@@ -14,7 +14,10 @@ from typing import Callable, Tuple
import azlmbr
import azlmbr.legacy.general as general
+import azlmbr.multiplayer as multiplayer
import azlmbr.debug
+import ly_test_tools.environment.waiter as waiter
+import ly_test_tools.environment.process_utils as process_utils
class FailFast(Exception):
@@ -66,6 +69,56 @@ class TestHelper:
TestHelper.wait_for_condition(lambda : general.is_in_game_mode(), 1.0)
Report.critical_result(msgtuple_success_fail, general.is_in_game_mode())
+ @staticmethod
+ def multiplayer_enter_game_mode(msgtuple_success_fail : Tuple[str, str], sv_default_player_spawn_asset : str):
+ # type: (tuple) -> None
+ """
+ :param msgtuple_success_fail: The tuple with the expected/unexpected messages for entering game mode.
+ :param sv_default_player_spawn_asset: The path to the network player prefab that will be automatically spawned upon entering gamemode. The engine default is "prefabs/player.network.spawnable"
+
+ :return: None
+ """
+
+ # looks for an expected line in a list of tracers lines
+ # lines: the tracer list of lines to search. options are section_tracer.warnings, section_tracer.errors, section_tracer.asserts, section_tracer.prints
+ # return: true if the line is found, otherwise false
+ def find_expected_line(expected_line, lines):
+ found_lines = [printInfo.message.strip() for printInfo in lines]
+ return expected_line in found_lines
+
+ def wait_for_critical_expected_line(expected_line, lines, time_out):
+ TestHelper.wait_for_condition(lambda : find_expected_line(expected_line, lines), time_out)
+ Report.critical_result(("Found expected line: " + expected_line, "Failed to find expected line: " + expected_line), find_expected_line(expected_line, lines))
+
+ def wait_for_critical_unexpected_line(unexpected_line, lines, time_out):
+ TestHelper.wait_for_condition(lambda : find_expected_line(unexpected_line, lines), time_out)
+ Report.critical_result(("Unexpected line not found: " + unexpected_line, "Unexpected line found: " + unexpected_line), not find_expected_line(unexpected_line, lines))
+
+
+ Report.info("Entering game mode")
+ if sv_default_player_spawn_asset :
+ general.set_cvar("sv_defaultPlayerSpawnAsset", sv_default_player_spawn_asset)
+
+ with Tracer() as section_tracer:
+ # enter game-mode.
+ # game-mode in multiplayer will also launch ServerLauncher.exe and connect to the editor
+ multiplayer.PythonEditorFuncs_enter_game_mode()
+
+ # make sure the server launcher binary exists
+ wait_for_critical_unexpected_line("LaunchEditorServer failed! The ServerLauncher binary is missing!", section_tracer.errors, 0.5)
+
+ # make sure the server launcher is running
+ waiter.wait_for(lambda: process_utils.process_exists("AutomatedTesting.ServerLauncher", ignore_extensions=True), timeout=5.0, exc=AssertionError("AutomatedTesting.ServerLauncher has NOT launched!"), interval=1.0)
+
+ # make sure the editor connects to the editor-server and sends the level data packet
+ wait_for_critical_expected_line("Editor is sending the editor-server the level data packet.", section_tracer.prints, 5.0)
+
+ # make sure the editor finally connects to the editor-server network simulation
+ wait_for_critical_expected_line("Editor-server ready. Editor has successfully connected to the editor-server's network simulation.", section_tracer.prints, 5.0)
+
+ TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 5.0)
+ Report.critical_result(msgtuple_success_fail, multiplayer.PythonEditorFuncs_is_in_game_mode())
+
@staticmethod
def exit_game_mode(msgtuple_success_fail : Tuple[str, str]):
# type: (tuple) -> None
diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt
new file mode 100644
index 0000000000..5e74d1e93b
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt
@@ -0,0 +1,23 @@
+#
+# 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
+#
+#
+
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
+ ly_add_pytest(
+ NAME AutomatedTesting::MultiplayerTests_Main
+ TEST_SUITE main
+ TEST_SERIAL
+ PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
+ RUNTIME_DEPENDENCIES
+ Legacy::Editor
+ AZ::AssetProcessor
+ AutomatedTesting.Assets
+ AutomatedTesting.ServerLauncher
+ COMPONENT
+ Multiplayer
+ )
+endif()
diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py
new file mode 100644
index 0000000000..9cecaa7fe8
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py
@@ -0,0 +1,33 @@
+"""
+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
+
+"""
+
+# This suite consists of all test cases that are under development and have not been verified yet.
+# Once they are verified, please move them to TestSuite_Active.py
+
+import pytest
+import os
+import sys
+
+
+sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
+
+from base import TestAutomationBase
+
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+class TestAutomation(TestAutomationBase):
+ def _run_prefab_test(self, request, workspace, editor, test_module, batch_mode=True, autotest_mode=True):
+ self._run_test(request, workspace, editor, test_module,
+ extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"],
+ batch_mode=batch_mode,
+ autotest_mode=autotest_mode)
+
+ def test_Multiplayer_AutoComponent_NetworkInput(self, request, workspace, editor, launcher_platform):
+ from .tests import Multiplayer_AutoComponent_NetworkInput as test_module
+ self._run_prefab_test(request, workspace, editor, test_module)
+
diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/__init__.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/__init__.py
new file mode 100644
index 0000000000..f5193b300e
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/__init__.py
@@ -0,0 +1,6 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py
new file mode 100644
index 0000000000..7b56213313
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py
@@ -0,0 +1,115 @@
+"""
+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
+"""
+
+
+# Test Case Title : Check that network input can be created, received by the authority, and processed
+
+
+# fmt: off
+class Tests():
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ find_network_player = ("Found network player", "Couldn't find network player")
+ found_lines = ("Expected log lines were found", "Expected log lines were not found")
+ found_unexpected_lines = ("Unexpected log lines were not found", "Unexpected log lines were found")
+# fmt: on
+
+
+def Multiplayer_AutoComponent_NetworkInput():
+ r"""
+ Summary:
+ Runs a test to make sure that network input can be sent from the autonomous player, received by the authority, and processed
+
+ Level Description:
+ - Dynamic
+ 1. Although the level is empty, when the server and editor connect the server will spawn and replicate the player network prefab.
+ a. The player network prefab has a NetworkTestPlayerComponent.AutoComponent and a script canvas attached which will listen for the CreateInput and ProcessInput events.
+ Print logs occur upon triggering the CreateInput and ProcessInput events along with their values; we are testing to make sure the expected events are values are recieved.
+ - Static
+ 1. This is an empty level. All the logic occurs on the Player.network.spawnable (see the above Dynamic description)
+
+
+ Expected Outcome:
+ We should see editor logs stating that network input has been created and processed.
+ However, if the script receives unexpected values for the Process event we will see print logs for bad data as well.
+
+ :return:
+ """
+ import azlmbr.legacy.general as general
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.utils import Tracer
+
+ from editor_python_test_tools.utils import TestHelper as helper
+ from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole
+
+
+ def find_expected_line(expected_line):
+ found_lines = [printInfo.message.strip() for printInfo in section_tracer.prints]
+ return expected_line in found_lines
+
+ def find_unexpected_line(expected_line):
+ return not find_expected_line(expected_line)
+
+ unexpected_lines = [
+ 'AutoComponent_NetworkInput received bad fwdback!',
+ 'AutoComponent_NetworkInput received bad leftright!',
+
+ ]
+ expected_lines = [
+ 'AutoComponent_NetworkInput ProcessInput called!',
+ 'AutoComponent_NetworkInput CreateInput called!',
+ ]
+
+ expected_lines_server = [
+ '(Script) - AutoComponent_NetworkInput ProcessInput called!',
+ ]
+
+ level_name = "AutoComponent_NetworkInput"
+ player_prefab_name = "Player"
+ player_prefab_path = f"levels/multiplayer/{level_name}/{player_prefab_name}.network.spawnable"
+
+ helper.init_idle()
+
+
+ # 1) Open Level
+ helper.open_level("Multiplayer", level_name)
+
+ with Tracer() as section_tracer:
+ # 2) Enter game mode
+ helper.multiplayer_enter_game_mode(Tests.enter_game_mode, player_prefab_path.lower())
+
+ # 3) Make sure the network player was spawned
+ player_id = general.find_game_entity(player_prefab_name)
+ Report.critical_result(Tests.find_network_player, player_id.IsValid())
+
+ # 4) Check the editor logs for expected and unexpected log output
+ EXPECTEDLINE_WAIT_TIME_SECONDS = 1.0
+ for expected_line in expected_lines :
+ helper.wait_for_condition(lambda: find_expected_line(expected_line), EXPECTEDLINE_WAIT_TIME_SECONDS)
+ Report.result(Tests.found_lines, find_expected_line(expected_line))
+
+ general.idle_wait_frames(1)
+ for unexpected_line in unexpected_lines :
+ Report.result(Tests.found_unexpected_lines, find_unexpected_line(unexpected_line))
+
+ # 5) Check the ServerLauncher logs for expected log output
+ # Since the editor has started a server launcher, the RemoteConsole with the default port=4600 will automatically be able to read the server logs
+ server_console = RemoteConsole()
+ server_console.start()
+ for line in expected_lines_server:
+ assert server_console.expect_log_line(line, EXPECTEDLINE_WAIT_TIME_SECONDS), f"Expected line not found: {line}"
+ server_console.stop()
+
+
+ # Exit game mode
+ helper.exit_game_mode(Tests.exit_game_mode)
+
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(Multiplayer_AutoComponent_NetworkInput)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py
index 63d3b58249..3d668a2085 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Main_Optimized.py
@@ -53,6 +53,27 @@ class EditorSingleTest_WithFileOverrides(EditorSingleTest):
for f in original_file_list:
fm._restore_file(f, file_list[f])
+@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
+@pytest.mark.SUITE_main
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+class TestAutomationWithPrefabSystemEnabled(EditorTestSuite):
+
+ global_extra_cmdline_args = ['-BatchMode', '-autotest_mode',
+ 'extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"]']
+
+ @staticmethod
+ def get_number_parallel_editors():
+ return 16
+
+ class C4982801_PhysXColliderShape_CanBeSelected(EditorSharedTest):
+ from .tests.collider import Collider_BoxShapeEditing as test_module
+
+ class C4982800_PhysXColliderShape_CanBeSelected(EditorSharedTest):
+ from .tests.collider import Collider_SphereShapeEditing as test_module
+
+ class C4982802_PhysXColliderShape_CanBeSelected(EditorSharedTest):
+ from .tests.collider import Collider_CapsuleShapeEditing as test_module
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_main
@@ -286,15 +307,6 @@ class TestAutomation(EditorTestSuite):
class C19723164_ShapeCollider_WontCrashEditor(EditorSharedTest):
from .tests.shape_collider import ShapeCollider_LargeNumberOfShapeCollidersWontCrashEditor as test_module
- class C4982800_PhysXColliderShape_CanBeSelected(EditorSharedTest):
- from .tests.collider import Collider_SphereShapeEditting as test_module
-
- class C4982801_PhysXColliderShape_CanBeSelected(EditorSharedTest):
- from .tests.collider import Collider_BoxShapeEditting as test_module
-
- class C4982802_PhysXColliderShape_CanBeSelected(EditorSharedTest):
- from .tests.collider import Collider_CapsuleShapeEditting as test_module
-
class C12905528_ForceRegion_WithNonTriggerCollider(EditorSharedTest):
from .tests.force_region import ForceRegion_WithNonTriggerColliderWarning as test_module
# Fixme: expected_lines = ["[Warning] (PhysX Force Region) - Please ensure collider component marked as trigger exists in entity"]
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py
index e5dd9adbb9..55e51dd2f8 100755
--- a/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/TestSuite_Periodic.py
@@ -401,19 +401,22 @@ class TestAutomation(TestAutomationBase):
self._run_test(request, workspace, editor, test_module)
@revert_physics_config
- def test_Collider_SphereShapeEditting(self, request, workspace, editor, launcher_platform):
- from .tests.collider import Collider_SphereShapeEditting as test_module
- self._run_test(request, workspace, editor, test_module)
+ def test_Collider_SphereShapeEditing(self, request, workspace, editor, launcher_platform):
+ from .tests.collider import Collider_SphereShapeEditing as test_module
+ self._run_test(request, workspace, editor, test_module,
+ extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"])
@revert_physics_config
- def test_Collider_BoxShapeEditting(self, request, workspace, editor, launcher_platform):
- from .tests.collider import Collider_BoxShapeEditting as test_module
- self._run_test(request, workspace, editor, test_module)
+ def test_Collider_BoxShapeEditing(self, request, workspace, editor, launcher_platform):
+ from .tests.collider import Collider_BoxShapeEditing as test_module
+ self._run_test(request, workspace, editor, test_module,
+ extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"])
@revert_physics_config
- def test_Collider_CapsuleShapeEditting(self, request, workspace, editor, launcher_platform):
- from .tests.collider import Collider_CapsuleShapeEditting as test_module
- self._run_test(request, workspace, editor, test_module)
+ def test_Collider_CapsuleShapeEditing(self, request, workspace, editor, launcher_platform):
+ from .tests.collider import Collider_CapsuleShapeEditing as test_module
+ self._run_test(request, workspace, editor, test_module,
+ extra_cmdline_args=["--regset=/Amazon/Preferences/EnablePrefabSystem=true"])
def test_ForceRegion_WithNonTriggerColliderWarning(self, request, workspace, editor, launcher_platform):
from .tests.force_region import ForceRegion_WithNonTriggerColliderWarning as test_module
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditting.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditing.py
similarity index 97%
rename from AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditting.py
rename to AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditing.py
index 68ff0b4edc..a6730c8559 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditting.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_BoxShapeEditing.py
@@ -19,7 +19,7 @@ class Tests():
# fmt: on
-def Collider_BoxShapeEditting():
+def Collider_BoxShapeEditing():
"""
Summary:
Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions
@@ -73,7 +73,7 @@ def Collider_BoxShapeEditting():
helper.init_idle()
# 1) Load the empty level
- helper.open_level("Physics", "Base")
+ helper.open_level("", "Base")
# 2) Create the test entity
test_entity = Entity.create_editor_entity("Test Entity")
@@ -102,4 +102,4 @@ def Collider_BoxShapeEditting():
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
- Report.start_test(Collider_BoxShapeEditting)
+ Report.start_test(Collider_BoxShapeEditing)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditting.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditing.py
similarity index 97%
rename from AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditting.py
rename to AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditing.py
index 7df12c68f0..12435cc54a 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditting.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_CapsuleShapeEditing.py
@@ -19,7 +19,7 @@ class Tests():
# fmt: on
-def Collider_CapsuleShapeEditting():
+def Collider_CapsuleShapeEditing():
"""
Summary:
Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions
@@ -74,7 +74,7 @@ def Collider_CapsuleShapeEditting():
helper.init_idle()
# 1) Load the empty level
- helper.open_level("Physics", "Base")
+ helper.open_level("", "Base")
# 2) Create the test entity
test_entity = Entity.create_editor_entity("Test Entity")
@@ -102,4 +102,4 @@ def Collider_CapsuleShapeEditting():
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
- Report.start_test(Collider_CapsuleShapeEditting)
+ Report.start_test(Collider_CapsuleShapeEditing)
diff --git a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditting.py b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditing.py
similarity index 96%
rename from AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditting.py
rename to AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditing.py
index bffd041d92..ef91235411 100644
--- a/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditting.py
+++ b/AutomatedTesting/Gem/PythonTests/Physics/tests/collider/Collider_SphereShapeEditing.py
@@ -19,7 +19,7 @@ class Tests():
# fmt: on
-def Collider_SphereShapeEditting():
+def Collider_SphereShapeEditing():
"""
Summary:
Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions
@@ -57,7 +57,7 @@ def Collider_SphereShapeEditting():
helper.init_idle()
# 1) Load the empty level
- helper.open_level("Physics", "Base")
+ helper.open_level("", "Base")
# 2) Create the test entity
test_entity = Entity.create_editor_entity("Test Entity")
@@ -90,4 +90,4 @@ def Collider_SphereShapeEditting():
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
- Report.start_test(Collider_SphereShapeEditting)
+ Report.start_test(Collider_SphereShapeEditing)
diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py
index 5337f0669c..479915752f 100644
--- a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py
+++ b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py
@@ -55,3 +55,11 @@ class TestAutomation(TestAutomationBase):
def test_PrefabBasicWorkflow_CreateAndDuplicatePrefab(self, request, workspace, editor, launcher_platform):
from .tests import PrefabBasicWorkflow_CreateAndDuplicatePrefab as test_module
self._run_prefab_test(request, workspace, editor, test_module)
+
+ def test_PrefabComplexWorflow_CreatePrefabOfChildEntity(self, request, workspace, editor, launcher_platform):
+ from .tests import PrefabComplexWorflow_CreatePrefabOfChildEntity as test_module
+ self._run_prefab_test(request, workspace, editor, test_module, autotest_mode=False)
+
+ def test_PrefabComplexWorflow_CreatePrefabInsidePrefab(self, request, workspace, editor, launcher_platform):
+ from .tests import PrefabComplexWorflow_CreatePrefabInsidePrefab as test_module
+ self._run_prefab_test(request, workspace, editor, test_module, autotest_mode=False)
diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py
new file mode 100644
index 0000000000..e14fc96449
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabInsidePrefab.py
@@ -0,0 +1,57 @@
+"""
+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
+"""
+
+def PrefabComplexWorflow_CreatePrefabInsidePrefab():
+ """
+ Test description:
+ - Creates an entity with a physx collider
+ - Creates a prefab "Outer_prefab" and an instance based of that entity
+ - Creates a prefab "Inner_prefab" inside "Outer_prefab" based the entity contained inside of it
+ Checks that the entity is correctly handlded by the prefab system checking the name and that it contains the physx collider
+ """
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.prefab_utils import Prefab
+
+ import PrefabTestUtils as prefab_test_utils
+
+ prefab_test_utils.open_base_tests_level()
+
+ # Creates a new Entity at the root level
+ # Asserts if creation didn't succeed
+ entity = EditorEntity.create_editor_entity_at((100.0, 100.0, 100.0), name = "TestEntity")
+ assert entity.id.IsValid(), "Couldn't create entity"
+ entity.add_component("PhysX Collider")
+ assert entity.has_component("PhysX Collider"), "Attempted to add a PhysX Collider but no physx collider collider was found afterwards"
+
+ # Create a prefab based on that entity
+ outer_prefab, outer_instance = Prefab.create_prefab([entity], "Outer_prefab")
+ # The test should be now inside the outer prefab instance.
+ entity = outer_instance.get_direct_child_entities()[0]
+ # We track if that is the same entity by checking the name and if it still contains the component that we created before
+ assert entity.get_name() == "TestEntity", f"Entity name inside outer_prefab doesn't match the original name, original:'TestEntity' current:'{entity.get_name()}'"
+ assert entity.has_component("PhysX Collider"), "Entity name inside outer_prefab doesn't have the collider component it should"
+
+ # Now, create another prefab, based on the entity that is inside outer_prefab
+ inner_prefab, inner_instance = Prefab.create_prefab([entity], "Inner_prefab")
+ # The test entity should now be inside the inner prefab instance
+ entity = inner_instance.get_direct_child_entities()[0]
+ # We track if that is the same entity by checking the name and if it still contains the component that we created before
+ assert entity.get_name() == "TestEntity", f"Entity name inside inner_prefab doesn't match the original name, original:'TestEntity' current:'{entity.get_name()}'"
+ assert entity.has_component("PhysX Collider"), "Entity name inside inner_prefab doesn't have the collider component it should"
+
+ # Verify hierarchy of entities:
+ # Outer_prefab
+ # |- Inner_prefab
+ # | |- TestEntity
+ assert entity.get_parent_id() == inner_instance.container_entity.id
+ assert inner_instance.container_entity.get_parent_id() == outer_instance.container_entity.id
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(PrefabComplexWorflow_CreatePrefabInsidePrefab)
diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py
new file mode 100644
index 0000000000..dec44d52be
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/PrefabComplexWorflow_CreatePrefabOfChildEntity.py
@@ -0,0 +1,52 @@
+"""
+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
+"""
+
+def PrefabComplexWorflow_CreatePrefabOfChildEntity():
+ """
+ Test description:
+ - Creates two entities, parent and child. Child entity has Parent entity as its parent.
+ - Creates a prefab of the child entity.
+ Test is successful if the new instanced prefab of the child has the parent entity id
+ """
+
+ CAR_PREFAB_FILE_NAME = 'car_prefab'
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.prefab_utils import Prefab
+
+ import PrefabTestUtils as prefab_test_utils
+
+ prefab_test_utils.open_base_tests_level()
+
+ # Creates a new Entity at the root level
+ # Asserts if creation didn't succeed
+ parent_entity = EditorEntity.create_editor_entity_at((100.0, 100.0, 100.0))
+ assert parent_entity.id.IsValid(), "Couldn't create parent entity"
+
+ child_entity = EditorEntity.create_editor_entity(parent_id=parent_entity.id)
+ assert child_entity.id.IsValid(), "Couldn't create child entity"
+ assert child_entity.get_world_translation().IsClose(parent_entity.get_world_translation()), f"Child entity position{child_entity.get_world_translation().ToString()}" \
+ f" is not located at the same position as the parent{parent_entity.get_world_translation().ToString()}"
+
+ # Asserts if prefab creation doesn't succeed
+ child_prefab, child_instance = Prefab.create_prefab([child_entity], CAR_PREFAB_FILE_NAME)
+ child_entity_on_child_instance = child_instance.get_direct_child_entities()[0]
+ assert child_instance.container_entity.get_parent_id().IsValid(), "Newly instanced entity has no parent"
+ assert child_instance.container_entity.get_parent_id() == parent_entity.id, "Newly instanced entity parent does not match the expected parent"
+ assert child_instance.container_entity.get_world_translation().IsClose(parent_entity.get_world_translation()), "Newly instanced entity position is not located at the same position as the parent"
+ # Move the parent position, it should update the child position
+ parent_entity.set_world_translation((200.0, 200.0, 200.0))
+ child_instance_translation = child_instance.container_entity.get_world_translation()
+ assert child_instance_translation.IsClose(azlmbr.math.Vector3(200.0, 200.0, 200.0)), f"Instance position position{child_instance_translation.ToString()} didn't get updated" \
+ f" to the same position as the parent{parent_entity.get_world_translation().ToString()}"
+ child_translation = child_entity_on_child_instance.get_world_translation()
+ assert child_translation.IsClose(azlmbr.math.Vector3(200.0, 200.0, 200.0)), f"Entity position{child_translation.ToString()} of the instance didn't get updated" \
+ f" to the same position as the parent{parent_entity.get_world_translation().ToString()}"
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(PrefabComplexWorflow_CreatePrefabOfChildEntity)
diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py
index 443a420b61..a6e8b97b63 100644
--- a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py
+++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py
@@ -23,7 +23,7 @@ def create_jobs(request):
jobDescriptorList = []
for platformInfo in request.enabledPlatforms:
jobDesc = azlmbr.asset.builder.JobDescriptor()
- jobDesc.jobKey = jobKeyName
+ jobDesc.jobKey = f'{jobKeyName}-{platformInfo.identifier}'
jobDesc.set_platform_identifier(platformInfo.identifier)
jobDescriptorList.append(jobDesc)
@@ -38,7 +38,7 @@ def on_create_jobs(args):
return create_jobs(request)
except:
log_exception_traceback()
- # returing back a default CreateJobsResponse() records an asset error
+ # returning back a default CreateJobsResponse() records an asset error
return azlmbr.asset.builder.CreateJobsResponse()
def process_file(request):
@@ -58,6 +58,7 @@ def process_file(request):
fileOutput = open(tempFilename, "w")
fileOutput.write('{}')
fileOutput.close()
+ print(f'Wrote mock asset file: {tempFilename}')
# generate a product asset file entry
subId = binascii.crc32(mockFilename.encode())
diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt
index 10cf949c25..733e8edf29 100644
--- a/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt
@@ -6,7 +6,11 @@
#
#
-if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
+ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
+
+include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_WHITEBOX Traits
+
+if(PAL_TRAIT_WHITEBOX_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::WhiteBoxTests
TEST_SUITE main
diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Android/PAL_android.cmake b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Android/PAL_android.cmake
new file mode 100644
index 0000000000..07aa0bb13d
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Android/PAL_android.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_WHITEBOX_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Linux/PAL_linux.cmake b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Linux/PAL_linux.cmake
new file mode 100644
index 0000000000..07aa0bb13d
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Linux/PAL_linux.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_WHITEBOX_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Mac/PAL_mac.cmake b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Mac/PAL_mac.cmake
new file mode 100644
index 0000000000..07aa0bb13d
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Mac/PAL_mac.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_WHITEBOX_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Windows/PAL_windows.cmake b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Windows/PAL_windows.cmake
new file mode 100644
index 0000000000..a83d56788a
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Windows/PAL_windows.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_WHITEBOX_TESTS_SUPPORTED TRUE)
diff --git a/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/iOS/PAL_ios.cmake b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/iOS/PAL_ios.cmake
new file mode 100644
index 0000000000..07aa0bb13d
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/iOS/PAL_ios.cmake
@@ -0,0 +1,9 @@
+#
+# 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
+#
+#
+
+set(PAL_TRAIT_WHITEBOX_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py
index 264f690534..303a012cda 100755
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_dependency_tests.py
@@ -47,82 +47,6 @@ class TestsAssetProcessorBatch_DependenycyTests(object):
"""
AssetProcessorBatch Dependency tests
"""
-
- @pytest.mark.test_case_id("C16877166")
- @pytest.mark.BAT
- @pytest.mark.assetpipeline
- # fmt:off
- def test_WindowsMacPlatforms_RunAPBatch_NotMissingDependency(self, ap_setup_fixture, asset_processor,
- workspace):
- # fmt:on
- """
- Engine Schema
- This test case has a conditional scenario depending on the existence of surfacetypes.xml in a project.
- Some projects have this file and others do not. Run the conditional scenario depending on the existence
- of the file in the project
- libs/materialeffects/surfacetypes.xml is listed as an entry engine_dependencies.xml
- libs/materialeffects/surfacetypes.xml is not listed as a missing dependency
- in the 'assetprocessorbatch' console output
-
- Test Steps:
- 1. Assets are pre-processed
- 2. Verify that engine_dependencies.xml exists
- 3. Verify engine_dependencies.xml has surfacetypes.xml present
- 4. Run Missing Dependency scanner against the engine_dependenciese.xml
- 5. Verify that Surfacetypes.xml is NOT in the missing depdencies output
- 6. Add the schema file which allows our xml parser to understand dependencies for our engine_dependencies file
- 7. Process assets
- 8. Run Missing Dependency scanner against the engine_dependenciese.xml
- 9. Verify that surfacetypes.xml is in the missing dependencies out
- """
-
- env = ap_setup_fixture
- BATCH_LOG_PATH = env["ap_batch_log_file"]
- asset_processor.create_temp_asset_root()
- asset_processor.add_relative_source_asset(os.path.join("Assets", "Engine", "Engine_Dependencies.xml"))
- asset_processor.add_scan_folder(os.path.join("Assets", "Engine"))
- asset_processor.add_relative_source_asset(os.path.join("Assets", "Engine", "Libs", "MaterialEffects", "surfacetypes.xml"))
-
- # Precondition: Assets are all processed
- asset_processor.batch_process()
-
- DEPENDENCIES_PATH = os.path.join(asset_processor.temp_project_cache(), "engine_dependencies.xml")
- assert os.path.exists(DEPENDENCIES_PATH), "The engine_dependencies.xml does not exist."
- surfacetypes_in_dependencies = False
- surfacetypes_missing_logline = False
-
- # Read engine_dependencies.xml to see if surfacetypes.xml is present
- with open(DEPENDENCIES_PATH, "r") as dependencies_file:
- for line in dependencies_file.readlines():
- if "surfacetypes.xml" in line:
- surfacetypes_in_dependencies = True
- logger.info("Surfacetypes.xml was listed in the engine_dependencies.xml file.")
- break
-
- if not surfacetypes_in_dependencies:
- logger.info("Surfacetypes.xml was not listed in the engine_dependencies.xml file.")
-
- _, output = asset_processor.batch_process(capture_output=True,
- extra_params="--dsp=%engine_dependencies.xml")
- log = APOutputParser(output)
- for _ in log.get_lines(run=-1, contains=["surfacetypes.xml", "Missing"]):
- surfacetypes_missing_logline = True
-
- assert surfacetypes_missing_logline, "Surfacetypes.xml not seen in the batch log as missing."
-
- # Add the schema file which allows our xml parser to understand dependencies for our engine_dependencies file
- asset_processor.add_relative_source_asset(os.path.join("Assets", "Engine", "Schema", "enginedependency.xmlschema"))
- asset_processor.batch_process()
-
- _, output = asset_processor.batch_process(capture_output=True,
- extra_params="--dsp=%engine_dependencies.xml")
- log = APOutputParser(output)
- surfacetypes_missing_logline = False
- for _ in log.get_lines(run=-1, contains=["surfacetypes.xml", "Missing"]):
- surfacetypes_missing_logline = True
-
- assert not surfacetypes_missing_logline, "Surfacetypes.xml not seen in the batch log as missing."
-
schemas = [
("C16877167", ".ent"),
("C16877168", "Environment.xml"),
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py
index f3483d9c1f..2d67bca8fe 100755
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py
@@ -329,7 +329,7 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
# or an expected behavior has changed. Processing bootstrap.cfg sometimes but not other times should not
# cause a failure in this test.
num_processed_assets = asset_processor_utils.get_num_processed_assets(output)
- assert num_processed_assets >= 8, f'Wrong number of successfully processed assets found in output: '\
+ assert num_processed_assets >= 6, f'Wrong number of successfully processed assets found in output: '\
'{num_processed_assets}'
missing_assets, _ = asset_processor.compare_assets_with_cache()
@@ -585,20 +585,18 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
3. Verify that logs exist for both AP Batch & AP GUI
"""
asset_processor.create_temp_asset_root()
+ asset_processor.create_temp_log_root()
LOG_PATH = {
"batch_log": workspace.paths.ap_batch_log(),
- "gui_log": workspace.paths.ap_gui_log(),
- "job_logs": workspace.paths.ap_job_logs(),
+ "gui_log": workspace.paths.ap_gui_log()
}
class LogTimes:
batch_log_start_time = 0
gui_log_start_time = 0
- job_logs_start_time = 0
batch_log_final_time = 0
gui_log_final_time = 0
- job_logs_final_time = 0
@staticmethod
def Report():
@@ -607,12 +605,10 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
Original Times:
Batch: {LogTimes.batch_log_start_time}
GUI: {LogTimes.gui_log_start_time}
- JobLogs:{LogTimes.job_logs_start_time}
Post-Run Times:
Batch: {LogTimes.batch_log_final_time}
GUI: {LogTimes.gui_log_final_time}
- JobLogs:{LogTimes.job_logs_final_time}
"""
)
@@ -629,23 +625,19 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
LogTimes.Report()
def check_existence(name, path):
- assert os.path.exists(path), f"{name} could not be located after running the AP."
+ assert os.path.exists(path), f"{name} could not be located {path} after running the AP."
# Check if log files previously exist and grab their modification times
update_times("_start_time")
# Run the Batch process
- assert asset_processor.batch_process(), "Batch process failed to successfully terminate"
+ assert asset_processor.batch_process(create_temp_log=False), "Batch process failed to successfully terminate"
- asset_processor.gui_process(quitonidle=True)
+ asset_processor.gui_process(quitonidle=True, create_temp_log=False)
# Check that the Logs directory exists (C1564055)
check_existence("Logs Directory", workspace.paths.ap_log_dir())
- # Check that the logs and JobLogs directory have updated modified times (C1564056)
- for key in LOG_PATH.keys():
- check_existence(key, LOG_PATH[key])
-
update_times("_final_time")
for key in LOG_PATH.keys():
@@ -708,6 +700,7 @@ class TestsAssetProcessorBatch_AllPlatforms(object):
@pytest.mark.BAT
@pytest.mark.assetpipeline
+ @pytest.mark.skip(reason="need to change assets from .slice files to an asset type that can have nested dependencies")
def test_validateNestedPreloadDependency_Found(self, asset_processor, ap_setup_fixture, workspace):
"""
Tests processing of a nested circular dependency and verifies that Asset Processor will return an error
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf
deleted file mode 100644
index 47571e39a9..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:7932fada1523fad4eb6ad5c13111bb4c00d6b0584ec8641060bf25f306b17e69
-size 84632
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx
deleted file mode 100644
index 165bc01a54..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:bf94b548eccb78432db65077124cadf20de975919b181d712fde081f59edd353
-size 38848
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt
new file mode 100644
index 0000000000..3d789f8b83
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt
@@ -0,0 +1 @@
+to be deleted
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf
deleted file mode 100644
index fcb3513ed0..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1675471085483e0bd252a5bdd4db1b365c66f16ac32a6e6dd70bb1c23df83fa5
-size 24160
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf
deleted file mode 100644
index fcb3513ed0..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1675471085483e0bd252a5bdd4db1b365c66f16ac32a6e6dd70bb1c23df83fa5
-size 24160
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png
deleted file mode 100644
index e012e887e7..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:21df6ab62f2572daa6d0710ad6819a728ee751a62170903a6773563d614aa51f
-size 15191
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png
deleted file mode 100644
index e012e887e7..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:21df6ab62f2572daa6d0710ad6819a728ee751a62170903a6773563d614aa51f
-size 15191
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk
deleted file mode 100644
index f525a402af..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f0b4750147acbcc6229a1043ed47ee48e7703a5241f27fc72976e95741144369
-size 2372
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png
deleted file mode 100644
index 47e2d35331..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:a036c3763b96079dde8505ad6995f8b717a777c78d7a434ac8de6f1ccb5d8dd1
-size 4327
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png
deleted file mode 100644
index b3b8fba4a1..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:cf55a4372d82d70d8cdcc95468367cd4fad7649d3fb99c4d85049977b506885c
-size 13429
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx
deleted file mode 100644
index 57fa7b327c..0000000000
--- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:1821d000b583821fd36ec73f91073d51ae90762225a34a81a74771c36236b5e1
-size 12963
diff --git a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py
index 15ba6690a1..50b89ab138 100644
--- a/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py
+++ b/AutomatedTesting/Gem/PythonTests/editor_test_testing/TestSuite_Main.py
@@ -15,6 +15,7 @@ import sys
import importlib
import re
+import ly_test_tools
from ly_test_tools import LAUNCHERS
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
@@ -25,8 +26,15 @@ import ly_test_tools.environment.process_utils as process_utils
import argparse, sys
-@pytest.mark.SUITE_main
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+def get_editor_launcher_platform():
+ if ly_test_tools.WINDOWS:
+ return "windows_editor"
+ elif ly_test_tools.LINUX:
+ return "linux_editor"
+ else:
+ return None
+
+@pytest.mark.parametrize("launcher_platform", [get_editor_launcher_platform()])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestEditorTest:
@@ -69,7 +77,7 @@ class TestEditorTest:
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite
@pytest.mark.SUITE_main
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+ @pytest.mark.parametrize("launcher_platform", [{get_editor_launcher_platform()}])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(EditorTestSuite):
class test_single(EditorSingleTest):
@@ -123,7 +131,7 @@ class TestEditorTest:
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorTestSuite
@pytest.mark.SUITE_main
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+ @pytest.mark.parametrize("launcher_platform", [{get_editor_launcher_platform()}])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(EditorTestSuite):
{module_class_code}
diff --git a/AutomatedTesting/Levels/Base/Base.prefab b/AutomatedTesting/Levels/Base/Base.prefab
new file mode 100644
index 0000000000..98495663b7
--- /dev/null
+++ b/AutomatedTesting/Levels/Base/Base.prefab
@@ -0,0 +1,53 @@
+{
+ "ContainerEntity": {
+ "Id": "ContainerEntity",
+ "Name": "Base",
+ "Components": {
+ "Component_[10182366347512475253]": {
+ "$type": "EditorPrefabComponent",
+ "Id": 10182366347512475253
+ },
+ "Component_[12917798267488243668]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 12917798267488243668
+ },
+ "Component_[3261249813163778338]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 3261249813163778338
+ },
+ "Component_[3837204912784440039]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 3837204912784440039
+ },
+ "Component_[4272963378099646759]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 4272963378099646759,
+ "Parent Entity": ""
+ },
+ "Component_[4848458548047175816]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 4848458548047175816
+ },
+ "Component_[5787060997243919943]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 5787060997243919943
+ },
+ "Component_[7804170251266531779]": {
+ "$type": "EditorLockComponent",
+ "Id": 7804170251266531779
+ },
+ "Component_[7874177159288365422]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 7874177159288365422
+ },
+ "Component_[8018146290632383969]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 8018146290632383969
+ },
+ "Component_[8452360690590857075]": {
+ "$type": "SelectionComponent",
+ "Id": 8452360690590857075
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.prefab b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.prefab
new file mode 100644
index 0000000000..78c88144fd
--- /dev/null
+++ b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.prefab
@@ -0,0 +1,525 @@
+{
+ "ContainerEntity": {
+ "Id": "Entity_[1146574390643]",
+ "Name": "Level",
+ "Components": {
+ "Component_[10641544592923449938]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 10641544592923449938
+ },
+ "Component_[12039882709170782873]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 12039882709170782873
+ },
+ "Component_[12265484671603697631]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 12265484671603697631
+ },
+ "Component_[14126657869720434043]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 14126657869720434043
+ },
+ "Component_[15230859088967841193]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 15230859088967841193,
+ "Parent Entity": ""
+ },
+ "Component_[16239496886950819870]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 16239496886950819870
+ },
+ "Component_[5688118765544765547]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 5688118765544765547
+ },
+ "Component_[6545738857812235305]": {
+ "$type": "SelectionComponent",
+ "Id": 6545738857812235305
+ },
+ "Component_[7247035804068349658]": {
+ "$type": "EditorPrefabComponent",
+ "Id": 7247035804068349658
+ },
+ "Component_[9307224322037797205]": {
+ "$type": "EditorLockComponent",
+ "Id": 9307224322037797205
+ },
+ "Component_[9562516168917670048]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 9562516168917670048
+ }
+ }
+ },
+ "Entities": {
+ "Entity_[1155164325235]": {
+ "Id": "Entity_[1155164325235]",
+ "Name": "Sun",
+ "Components": {
+ "Component_[10440557478882592717]": {
+ "$type": "SelectionComponent",
+ "Id": 10440557478882592717
+ },
+ "Component_[13620450453324765907]": {
+ "$type": "EditorLockComponent",
+ "Id": 13620450453324765907
+ },
+ "Component_[2134313378593666258]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 2134313378593666258
+ },
+ "Component_[234010807770404186]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 234010807770404186
+ },
+ "Component_[2970359110423865725]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 2970359110423865725
+ },
+ "Component_[3722854130373041803]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 3722854130373041803
+ },
+ "Component_[5992533738676323195]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 5992533738676323195
+ },
+ "Component_[7378860763541895402]": {
+ "$type": "AZ::Render::EditorDirectionalLightComponent",
+ "Id": 7378860763541895402,
+ "Controller": {
+ "Configuration": {
+ "Intensity": 1.0,
+ "CameraEntityId": "",
+ "ShadowFilterMethod": 1
+ }
+ }
+ },
+ "Component_[7892834440890947578]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 7892834440890947578,
+ "Parent Entity": "Entity_[1176639161715]",
+ "Transform Data": {
+ "Translate": [
+ 0.0,
+ 0.0,
+ 13.487043380737305
+ ],
+ "Rotate": [
+ -76.13099670410156,
+ -0.847000002861023,
+ -15.8100004196167
+ ]
+ }
+ },
+ "Component_[8599729549570828259]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 8599729549570828259
+ },
+ "Component_[952797371922080273]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 952797371922080273
+ }
+ }
+ },
+ "Entity_[1159459292531]": {
+ "Id": "Entity_[1159459292531]",
+ "Name": "Ground",
+ "Components": {
+ "Component_[11701138785793981042]": {
+ "$type": "SelectionComponent",
+ "Id": 11701138785793981042
+ },
+ "Component_[12260880513256986252]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 12260880513256986252
+ },
+ "Component_[13711420870643673468]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 13711420870643673468
+ },
+ "Component_[138002849734991713]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 138002849734991713
+ },
+ "Component_[16578565737331764849]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 16578565737331764849,
+ "Parent Entity": "Entity_[1176639161715]"
+ },
+ "Component_[16919232076966545697]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 16919232076966545697
+ },
+ "Component_[5182430712893438093]": {
+ "$type": "EditorMaterialComponent",
+ "Id": 5182430712893438093,
+ "materialSlots": [
+ {
+ "id": {
+ "materialSlotStableId": 803645540
+ }
+ },
+ {
+ "id": {
+ "materialSlotStableId": 803645540
+ }
+ }
+ ],
+ "materialSlotsByLod": [
+ [
+ {
+ "id": {
+ "lodIndex": 0,
+ "materialSlotStableId": 803645540
+ }
+ }
+ ],
+ [
+ {
+ "id": {
+ "lodIndex": 0,
+ "materialSlotStableId": 803645540
+ }
+ }
+ ]
+ ]
+ },
+ "Component_[5675108321710651991]": {
+ "$type": "AZ::Render::EditorMeshComponent",
+ "Id": 5675108321710651991,
+ "Controller": {
+ "Configuration": {
+ "ModelAsset": {
+ "assetId": {
+ "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
+ "subId": 277889906
+ },
+ "assetHint": "objects/groudplane/groundplane_512x512m.azmodel"
+ }
+ }
+ }
+ },
+ "Component_[5681893399601237518]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 5681893399601237518
+ },
+ "Component_[592692962543397545]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 592692962543397545
+ },
+ "Component_[7090012899106946164]": {
+ "$type": "EditorLockComponent",
+ "Id": 7090012899106946164
+ },
+ "Component_[9410832619875640998]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 9410832619875640998
+ }
+ }
+ },
+ "Entity_[1163754259827]": {
+ "Id": "Entity_[1163754259827]",
+ "Name": "Camera",
+ "Components": {
+ "Component_[11895140916889160460]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 11895140916889160460
+ },
+ "Component_[16880285896855930892]": {
+ "$type": "{CA11DA46-29FF-4083-B5F6-E02C3A8C3A3D} EditorCameraComponent",
+ "Id": 16880285896855930892,
+ "Controller": {
+ "Configuration": {
+ "Field of View": 55.0,
+ "EditorEntityId": 12554887233631987164
+ }
+ }
+ },
+ "Component_[17187464423780271193]": {
+ "$type": "EditorLockComponent",
+ "Id": 17187464423780271193
+ },
+ "Component_[17495696818315413311]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 17495696818315413311
+ },
+ "Component_[18086214374043522055]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 18086214374043522055,
+ "Parent Entity": "Entity_[1176639161715]",
+ "Transform Data": {
+ "Translate": [
+ -2.3000001907348633,
+ -3.9368600845336914,
+ 1.0
+ ],
+ "Rotate": [
+ -2.050307512283325,
+ 1.9552897214889526,
+ -43.623355865478516
+ ]
+ }
+ },
+ "Component_[18387556550380114975]": {
+ "$type": "SelectionComponent",
+ "Id": 18387556550380114975
+ },
+ "Component_[2654521436129313160]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 2654521436129313160
+ },
+ "Component_[5265045084611556958]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 5265045084611556958
+ },
+ "Component_[7169798125182238623]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 7169798125182238623
+ },
+ "Component_[7255796294953281766]": {
+ "$type": "GenericComponentWrapper",
+ "Id": 7255796294953281766,
+ "m_template": {
+ "$type": "FlyCameraInputComponent"
+ }
+ },
+ "Component_[8866210352157164042]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 8866210352157164042
+ },
+ "Component_[9129253381063760879]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 9129253381063760879
+ }
+ }
+ },
+ "Entity_[1168049227123]": {
+ "Id": "Entity_[1168049227123]",
+ "Name": "Grid",
+ "Components": {
+ "Component_[11443347433215807130]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 11443347433215807130
+ },
+ "Component_[11779275529534764488]": {
+ "$type": "SelectionComponent",
+ "Id": 11779275529534764488
+ },
+ "Component_[14249419413039427459]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 14249419413039427459
+ },
+ "Component_[15448581635946161318]": {
+ "$type": "AZ::Render::EditorGridComponent",
+ "Id": 15448581635946161318,
+ "Controller": {
+ "Configuration": {
+ "primarySpacing": 4.0,
+ "primaryColor": [
+ 0.501960813999176,
+ 0.501960813999176,
+ 0.501960813999176
+ ],
+ "secondarySpacing": 0.5,
+ "secondaryColor": [
+ 0.250980406999588,
+ 0.250980406999588,
+ 0.250980406999588
+ ]
+ }
+ }
+ },
+ "Component_[1843303322527297409]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 1843303322527297409
+ },
+ "Component_[380249072065273654]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 380249072065273654,
+ "Parent Entity": "Entity_[1176639161715]"
+ },
+ "Component_[7476660583684339787]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 7476660583684339787
+ },
+ "Component_[7557626501215118375]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 7557626501215118375
+ },
+ "Component_[7984048488947365511]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 7984048488947365511
+ },
+ "Component_[8118181039276487398]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 8118181039276487398
+ },
+ "Component_[9189909764215270515]": {
+ "$type": "EditorLockComponent",
+ "Id": 9189909764215270515
+ }
+ }
+ },
+ "Entity_[1176639161715]": {
+ "Id": "Entity_[1176639161715]",
+ "Name": "Atom Default Environment",
+ "Components": {
+ "Component_[10757302973393310045]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 10757302973393310045,
+ "Parent Entity": "Entity_[1146574390643]"
+ },
+ "Component_[14505817420424255464]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 14505817420424255464,
+ "ComponentOrderEntryArray": [
+ {
+ "ComponentId": 10757302973393310045
+ }
+ ]
+ },
+ "Component_[14988041764659020032]": {
+ "$type": "EditorLockComponent",
+ "Id": 14988041764659020032
+ },
+ "Component_[15808690248755038124]": {
+ "$type": "SelectionComponent",
+ "Id": 15808690248755038124
+ },
+ "Component_[15900837685796817138]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 15900837685796817138
+ },
+ "Component_[3298767348226484884]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 3298767348226484884
+ },
+ "Component_[4076975109609220594]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 4076975109609220594
+ },
+ "Component_[5679760548946028854]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 5679760548946028854
+ },
+ "Component_[5855590796136709437]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 5855590796136709437,
+ "ChildEntityOrderEntryArray": [
+ {
+ "EntityId": "Entity_[1155164325235]"
+ },
+ {
+ "EntityId": "Entity_[1180934129011]",
+ "SortIndex": 1
+ },
+ {
+ "EntityId": "",
+ "SortIndex": 2
+ },
+ {
+ "EntityId": "Entity_[1168049227123]",
+ "SortIndex": 3
+ },
+ {
+ "EntityId": "Entity_[1163754259827]",
+ "SortIndex": 4
+ },
+ {
+ "EntityId": "Entity_[1159459292531]",
+ "SortIndex": 5
+ }
+ ]
+ },
+ "Component_[9277695270015777859]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 9277695270015777859
+ }
+ }
+ },
+ "Entity_[1180934129011]": {
+ "Id": "Entity_[1180934129011]",
+ "Name": "Global Sky",
+ "Components": {
+ "Component_[11231930600558681245]": {
+ "$type": "AZ::Render::EditorHDRiSkyboxComponent",
+ "Id": 11231930600558681245,
+ "Controller": {
+ "Configuration": {
+ "CubemapAsset": {
+ "assetId": {
+ "guid": "{215E47FD-D181-5832-B1AB-91673ABF6399}",
+ "subId": 1000
+ },
+ "assetHint": "lightingpresets/highcontrast/goegap_4k_skyboxcm.exr.streamingimage"
+ }
+ }
+ }
+ },
+ "Component_[11980494120202836095]": {
+ "$type": "SelectionComponent",
+ "Id": 11980494120202836095
+ },
+ "Component_[1428633914413949476]": {
+ "$type": "EditorLockComponent",
+ "Id": 1428633914413949476
+ },
+ "Component_[14936200426671614999]": {
+ "$type": "AZ::Render::EditorImageBasedLightComponent",
+ "Id": 14936200426671614999,
+ "Controller": {
+ "Configuration": {
+ "diffuseImageAsset": {
+ "assetId": {
+ "guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
+ "subId": 3000
+ },
+ "assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_ibldiffuse.exr.streamingimage"
+ },
+ "specularImageAsset": {
+ "assetId": {
+ "guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
+ "subId": 2000
+ },
+ "assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_iblspecular.exr.streamingimage"
+ }
+ }
+ }
+ },
+ "Component_[14994774102579326069]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 14994774102579326069
+ },
+ "Component_[15417479889044493340]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 15417479889044493340
+ },
+ "Component_[15826613364991382688]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 15826613364991382688
+ },
+ "Component_[1665003113283562343]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 1665003113283562343
+ },
+ "Component_[3704934735944502280]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 3704934735944502280
+ },
+ "Component_[5698542331457326479]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 5698542331457326479
+ },
+ "Component_[6644513399057217122]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 6644513399057217122,
+ "Parent Entity": "Entity_[1176639161715]"
+ },
+ "Component_[931091830724002070]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 931091830724002070
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.scriptcanvas b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.scriptcanvas
new file mode 100644
index 0000000000..2f8a434108
--- /dev/null
+++ b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.scriptcanvas
@@ -0,0 +1,1827 @@
+{
+ "Type": "JsonSerialization",
+ "Version": 1,
+ "ClassName": "ScriptCanvasData",
+ "ClassData": {
+ "m_scriptCanvas": {
+ "Id": {
+ "id": 20239954977260
+ },
+ "Name": "AutoComponent_NetworkInput",
+ "Components": {
+ "Component_[14059414856740480991]": {
+ "$type": "EditorGraphVariableManagerComponent",
+ "Id": 14059414856740480991,
+ "m_variableData": {
+ "m_nameVariableMap": [
+ {
+ "Key": {
+ "m_id": "{720D213F-AA7A-48B0-ABBB-A3756C528CF9}"
+ },
+ "Value": {
+ "Datum": {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.25
+ },
+ "VariableId": {
+ "m_id": "{720D213F-AA7A-48B0-ABBB-A3756C528CF9}"
+ },
+ "VariableName": "leftright"
+ }
+ },
+ {
+ "Key": {
+ "m_id": "{B2E338E9-2ACB-42FC-B0BE-EDA14A8A86AD}"
+ },
+ "Value": {
+ "Datum": {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 1.0
+ },
+ "VariableId": {
+ "m_id": "{B2E338E9-2ACB-42FC-B0BE-EDA14A8A86AD}"
+ },
+ "VariableName": "fwdback"
+ }
+ },
+ {
+ "Key": {
+ "m_id": "{D843B13F-B3C7-4619-8092-7164EB1D7888}"
+ },
+ "Value": {
+ "Datum": {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 20.0
+ },
+ "VariableId": {
+ "m_id": "{D843B13F-B3C7-4619-8092-7164EB1D7888}"
+ },
+ "VariableName": "VELOCITY"
+ }
+ }
+ ]
+ }
+ },
+ "Component_[642525765775040231]": {
+ "$type": "{4D755CA9-AB92-462C-B24F-0B3376F19967} Graph",
+ "Id": 642525765775040231,
+ "m_graphData": {
+ "m_nodes": [
+ {
+ "Id": {
+ "id": 20265724781036
+ },
+ "Name": "SC-Node(NotEqualTo)",
+ "Components": {
+ "Component_[12036973200504716538]": {
+ "$type": "NotEqualTo",
+ "Id": 12036973200504716538,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{6D0EF497-7C52-432B-9301-7BAB26F4F5A5}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Result",
+ "DisplayDataType": {
+ "m_type": 0
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{AE7E453C-15DE-47D2-954A-05C3895B7AC6}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "Signal to perform the evaluation when desired.",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{AC364E17-A9A1-42DB-A29D-7B2D666E4287}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "True",
+ "toolTip": "Signaled if the result of the operation is true.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{0754AC37-61A6-42A7-B4EC-D35D18D27960}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "False",
+ "toolTip": "Signaled if the result of the operation is false.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{57EBC15B-452E-49B3-8BD3-4FBBB07F1F14}"
+ },
+ "DynamicTypeOverride": 3,
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Value A",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DynamicGroup": {
+ "Value": 3545012108
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{21864AEE-7954-4F68-82C6-573C175724EF}"
+ },
+ "DynamicTypeOverride": 3,
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Value B",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DynamicGroup": {
+ "Value": 3545012108
+ },
+ "DataType": 1,
+ "IsReference": true,
+ "VariableReference": {
+ "m_id": "{720D213F-AA7A-48B0-ABBB-A3756C528CF9}"
+ }
+ }
+ ],
+ "Datums": [
+ {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.0,
+ "label": "Value A"
+ },
+ {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.0,
+ "label": "Value B"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20257134846444
+ },
+ "Name": "SC-Node(NotEqualTo)",
+ "Components": {
+ "Component_[12036973200504716538]": {
+ "$type": "NotEqualTo",
+ "Id": 12036973200504716538,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{6D0EF497-7C52-432B-9301-7BAB26F4F5A5}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Result",
+ "DisplayDataType": {
+ "m_type": 0
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{AE7E453C-15DE-47D2-954A-05C3895B7AC6}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "Signal to perform the evaluation when desired.",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{AC364E17-A9A1-42DB-A29D-7B2D666E4287}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "True",
+ "toolTip": "Signaled if the result of the operation is true.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{0754AC37-61A6-42A7-B4EC-D35D18D27960}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "False",
+ "toolTip": "Signaled if the result of the operation is false.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{57EBC15B-452E-49B3-8BD3-4FBBB07F1F14}"
+ },
+ "DynamicTypeOverride": 3,
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Value A",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DynamicGroup": {
+ "Value": 3545012108
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{21864AEE-7954-4F68-82C6-573C175724EF}"
+ },
+ "DynamicTypeOverride": 3,
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Value B",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DynamicGroup": {
+ "Value": 3545012108
+ },
+ "DataType": 1,
+ "IsReference": true,
+ "VariableReference": {
+ "m_id": "{B2E338E9-2ACB-42FC-B0BE-EDA14A8A86AD}"
+ }
+ }
+ ],
+ "Datums": [
+ {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.0,
+ "label": "Value A"
+ },
+ {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.0,
+ "label": "Value B"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20278609682924
+ },
+ "Name": "SC-Node(Print)",
+ "Components": {
+ "Component_[12996217042650310160]": {
+ "$type": "Print",
+ "Id": 12996217042650310160,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{D994D58A-DBF1-4929-B779-F0D2CBAD2F0D}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "Input signal",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{233C15BC-0186-4A7F-B272-6B2C020DE57A}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Out",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ }
+ ],
+ "m_format": "AutoComponent_NetworkInput ProcessInput called!",
+ "m_unresolvedString": [
+ "AutoComponent_NetworkInput ProcessInput called!"
+ ]
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20244249944556
+ },
+ "Name": "SC-Node(CreateFromValues)",
+ "Components": {
+ "Component_[16858161274259468878]": {
+ "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method",
+ "Id": 16858161274259468878,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{7CF3B6C0-FE59-4E16-ABC6-E7CC8AFA8EF3}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "fwdBack",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DataType": 1,
+ "IsReference": true,
+ "VariableReference": {
+ "m_id": "{B2E338E9-2ACB-42FC-B0BE-EDA14A8A86AD}"
+ }
+ },
+ {
+ "id": {
+ "m_id": "{02473A8A-A0F0-4E73-8999-0B16D17E8E2A}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "leftRight",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DataType": 1,
+ "IsReference": true,
+ "VariableReference": {
+ "m_id": "{720D213F-AA7A-48B0-ABBB-A3756C528CF9}"
+ }
+ },
+ {
+ "id": {
+ "m_id": "{514CDDAA-290F-4758-B28F-4003E719E635}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{E3A94716-C880-4D6D-ADD6-34D019161ED1}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Out",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{90E52F81-54E0-4C63-9881-B661FB5D87D1}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Result: NetworkTestPlayerComponentNetworkInput",
+ "DisplayDataType": {
+ "m_type": 4,
+ "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}"
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ }
+ ],
+ "Datums": [
+ {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.0,
+ "label": "fwdBack"
+ },
+ {
+ "scriptCanvasType": {
+ "m_type": 3
+ },
+ "isNullPointer": false,
+ "$type": "double",
+ "value": 0.0,
+ "label": "leftRight"
+ }
+ ],
+ "methodType": 2,
+ "methodName": "CreateFromValues",
+ "className": "NetworkTestPlayerComponentNetworkInput",
+ "resultSlotIDs": [
+ {}
+ ],
+ "inputSlots": [
+ {
+ "m_id": "{7CF3B6C0-FE59-4E16-ABC6-E7CC8AFA8EF3}"
+ },
+ {
+ "m_id": "{02473A8A-A0F0-4E73-8999-0B16D17E8E2A}"
+ }
+ ],
+ "prettyClassName": "NetworkTestPlayerComponentNetworkInput"
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20252839879148
+ },
+ "Name": "EBusEventHandler",
+ "Components": {
+ "Component_[1734984895901771768]": {
+ "$type": "EBusEventHandler",
+ "Id": 1734984895901771768,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{41899533-66B3-423F-8BE2-A624A1FB6FCB}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Connect",
+ "toolTip": "Connect this event handler to the specified entity.",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{65C09819-1B00-4BA8-B6E0-8DD6D8B44A36}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Disconnect",
+ "toolTip": "Disconnect this event handler.",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{B7437693-34D0-4BDE-8516-2CADB9F509BF}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "OnConnected",
+ "toolTip": "Signaled when a connection has taken place.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{BCE36ED4-0899-4403-826A-FE89BE033A0A}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "OnDisconnected",
+ "toolTip": "Signaled when this event handler is disconnected.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{796993F4-685D-4A85-A0CA-032E3466FB57}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "OnFailure",
+ "toolTip": "Signaled when it is not possible to connect this handler.",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{680E9668-87B4-4FF2-AA24-EB8F11352A49}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Source",
+ "toolTip": "ID used to connect on a specific Event address (Type: EntityId)",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{ADF9B366-8324-4C1E-B601-C059DA70FDDE}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Result: NetworkTestPlayerComponentNetworkInput",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{3301102C-AD42-48A0-8764-D2D4D31E0C75}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Number",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{B831AC60-7641-4B74-9829-26A3576B4766}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "ExecutionSlot:CreateInput",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ },
+ "IsLatent": true
+ },
+ {
+ "id": {
+ "m_id": "{8F69FA2E-28D8-4DF1-A4B5-AEF3985095C5}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "NetworkTestPlayerComponentNetworkInput",
+ "DisplayDataType": {
+ "m_type": 4,
+ "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}"
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{BE3E3F84-E91C-4F6C-B148-E13BF01B5FBC}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Number",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{4C8F2908-12B0-4C35-8468-31D3D4DF36AA}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "ExecutionSlot:ProcessInput",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ },
+ "IsLatent": true
+ }
+ ],
+ "Datums": [
+ {
+ "scriptCanvasType": {
+ "m_type": 1
+ },
+ "isNullPointer": false,
+ "$type": "EntityId",
+ "value": {
+ "id": 2901262558
+ },
+ "label": "Source"
+ },
+ {
+ "scriptCanvasType": {
+ "m_type": 4,
+ "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}"
+ },
+ "isNullPointer": false,
+ "$type": "NetworkTestPlayerComponentNetworkInput",
+ "label": "Result: NetworkTestPlayerComponentNetworkInput"
+ }
+ ],
+ "m_eventMap": [
+ {
+ "Key": {
+ "Value": 78438309
+ },
+ "Value": {
+ "m_eventName": "CreateInput",
+ "m_eventId": {
+ "Value": 78438309
+ },
+ "m_eventSlotId": {
+ "m_id": "{B831AC60-7641-4B74-9829-26A3576B4766}"
+ },
+ "m_resultSlotId": {
+ "m_id": "{ADF9B366-8324-4C1E-B601-C059DA70FDDE}"
+ },
+ "m_parameterSlotIds": [
+ {
+ "m_id": "{3301102C-AD42-48A0-8764-D2D4D31E0C75}"
+ }
+ ],
+ "m_numExpectedArguments": 1
+ }
+ },
+ {
+ "Key": {
+ "Value": 1793364217
+ },
+ "Value": {
+ "m_eventName": "ProcessInput",
+ "m_eventId": {
+ "Value": 1793364217
+ },
+ "m_eventSlotId": {
+ "m_id": "{4C8F2908-12B0-4C35-8468-31D3D4DF36AA}"
+ },
+ "m_parameterSlotIds": [
+ {
+ "m_id": "{8F69FA2E-28D8-4DF1-A4B5-AEF3985095C5}"
+ },
+ {
+ "m_id": "{BE3E3F84-E91C-4F6C-B148-E13BF01B5FBC}"
+ }
+ ],
+ "m_numExpectedArguments": 2
+ }
+ }
+ ],
+ "m_ebusName": "NetworkTestPlayerComponentBusHandler",
+ "m_busId": {
+ "Value": 3690077280
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20248544911852
+ },
+ "Name": "SC-Node(ExtractProperty)",
+ "Components": {
+ "Component_[2395597035843331661]": {
+ "$type": "ExtractProperty",
+ "Id": 2395597035843331661,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{C80C50EE-F216-4F44-B107-6B35354AFD52}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "When signaled assigns property values using the supplied source input",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{C69C098D-D667-4DC7-85E5-AFD119727D94}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Out",
+ "toolTip": "Signaled after all property haves have been pushed to the output slots",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{D387C800-352B-4B01-8765-4F4B40DF45CB}"
+ },
+ "DynamicTypeOverride": 1,
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Source",
+ "toolTip": "The value on which to extract properties from.",
+ "DisplayDataType": {
+ "m_type": 4,
+ "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}"
+ },
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{0C03D491-DE25-46C2-BF09-14769FA49FDB}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "FwdBack: Number",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ },
+ {
+ "id": {
+ "m_id": "{4C13F9EF-60BF-4AD1-8FA9-66F46455411C}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "LeftRight: Number",
+ "DisplayDataType": {
+ "m_type": 3
+ },
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 2
+ },
+ "DataType": 1
+ }
+ ],
+ "Datums": [
+ {
+ "scriptCanvasType": {
+ "m_type": 4,
+ "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}"
+ },
+ "isNullPointer": false,
+ "$type": "NetworkTestPlayerComponentNetworkInput",
+ "label": "Source"
+ }
+ ],
+ "m_dataType": {
+ "m_type": 4,
+ "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}"
+ },
+ "m_propertyAccounts": [
+ {
+ "m_propertySlotId": {
+ "m_id": "{0C03D491-DE25-46C2-BF09-14769FA49FDB}"
+ },
+ "m_propertyType": {
+ "m_type": 3
+ },
+ "m_propertyName": "FwdBack"
+ },
+ {
+ "m_propertySlotId": {
+ "m_id": "{4C13F9EF-60BF-4AD1-8FA9-66F46455411C}"
+ },
+ "m_propertyType": {
+ "m_type": 3
+ },
+ "m_propertyName": "LeftRight"
+ }
+ ]
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20270019748332
+ },
+ "Name": "SC-Node(Print)",
+ "Components": {
+ "Component_[7568030783460446634]": {
+ "$type": "Print",
+ "Id": 7568030783460446634,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{733AA75D-022C-45E9-9D0F-3EF9A1633ADC}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "Input signal",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{2E77B0FC-DE56-4D78-9A59-152B7A0666F3}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Out",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ }
+ ],
+ "m_format": "AutoComponent_NetworkInput received bad fwdback!",
+ "m_unresolvedString": [
+ "AutoComponent_NetworkInput received bad fwdback!"
+ ]
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20274314715628
+ },
+ "Name": "SC-Node(Print)",
+ "Components": {
+ "Component_[7568030783460446634]": {
+ "$type": "Print",
+ "Id": 7568030783460446634,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{733AA75D-022C-45E9-9D0F-3EF9A1633ADC}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "Input signal",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{2E77B0FC-DE56-4D78-9A59-152B7A0666F3}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Out",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ }
+ ],
+ "m_format": "AutoComponent_NetworkInput received bad leftright!",
+ "m_unresolvedString": [
+ "AutoComponent_NetworkInput received bad leftright!"
+ ]
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20261429813740
+ },
+ "Name": "SC-Node(Print)",
+ "Components": {
+ "Component_[8131385522131771125]": {
+ "$type": "Print",
+ "Id": 8131385522131771125,
+ "Slots": [
+ {
+ "id": {
+ "m_id": "{2B6DB3BC-AA87-4280-B4C3-42C1EE17CBA3}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "In",
+ "toolTip": "Input signal",
+ "Descriptor": {
+ "ConnectionType": 1,
+ "SlotType": 1
+ }
+ },
+ {
+ "id": {
+ "m_id": "{68F1C47B-3127-4CBA-AC9B-5B9B736C70AD}"
+ },
+ "contracts": [
+ {
+ "$type": "SlotTypeContract"
+ }
+ ],
+ "slotName": "Out",
+ "Descriptor": {
+ "ConnectionType": 2,
+ "SlotType": 1
+ }
+ }
+ ],
+ "m_format": "AutoComponent_NetworkInput CreateInput called!",
+ "m_unresolvedString": [
+ "AutoComponent_NetworkInput CreateInput called!"
+ ]
+ }
+ }
+ }
+ ],
+ "m_connections": [
+ {
+ "Id": {
+ "id": 20282904650220
+ },
+ "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:CreateInput), destEndpoint=(Print: In)",
+ "Components": {
+ "Component_[3586317167340048684]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 3586317167340048684,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20252839879148
+ },
+ "slotId": {
+ "m_id": "{B831AC60-7641-4B74-9829-26A3576B4766}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20261429813740
+ },
+ "slotId": {
+ "m_id": "{2B6DB3BC-AA87-4280-B4C3-42C1EE17CBA3}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20287199617516
+ },
+ "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:CreateInput), destEndpoint=(CreateFromValues: In)",
+ "Components": {
+ "Component_[15956251897822268937]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 15956251897822268937,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20252839879148
+ },
+ "slotId": {
+ "m_id": "{B831AC60-7641-4B74-9829-26A3576B4766}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20244249944556
+ },
+ "slotId": {
+ "m_id": "{514CDDAA-290F-4758-B28F-4003E719E635}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20291494584812
+ },
+ "Name": "srcEndpoint=(CreateFromValues: Result: NetworkTestPlayerComponentNetworkInput), destEndpoint=(NetworkTestPlayerComponentBusHandler Handler: Result: NetworkTestPlayerComponentNetworkInput)",
+ "Components": {
+ "Component_[3864080489501353126]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 3864080489501353126,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20244249944556
+ },
+ "slotId": {
+ "m_id": "{90E52F81-54E0-4C63-9881-B661FB5D87D1}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20252839879148
+ },
+ "slotId": {
+ "m_id": "{ADF9B366-8324-4C1E-B601-C059DA70FDDE}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20295789552108
+ },
+ "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:ProcessInput), destEndpoint=(Print: In)",
+ "Components": {
+ "Component_[8628095809445337119]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 8628095809445337119,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20252839879148
+ },
+ "slotId": {
+ "m_id": "{4C8F2908-12B0-4C35-8468-31D3D4DF36AA}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20278609682924
+ },
+ "slotId": {
+ "m_id": "{D994D58A-DBF1-4929-B779-F0D2CBAD2F0D}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20300084519404
+ },
+ "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:ProcessInput), destEndpoint=(Extract Properties: In)",
+ "Components": {
+ "Component_[10621112306443381493]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 10621112306443381493,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20252839879148
+ },
+ "slotId": {
+ "m_id": "{4C8F2908-12B0-4C35-8468-31D3D4DF36AA}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20248544911852
+ },
+ "slotId": {
+ "m_id": "{C80C50EE-F216-4F44-B107-6B35354AFD52}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20304379486700
+ },
+ "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: NetworkTestPlayerComponentNetworkInput), destEndpoint=(Extract Properties: Source)",
+ "Components": {
+ "Component_[14013500888143163469]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 14013500888143163469,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20252839879148
+ },
+ "slotId": {
+ "m_id": "{8F69FA2E-28D8-4DF1-A4B5-AEF3985095C5}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20248544911852
+ },
+ "slotId": {
+ "m_id": "{D387C800-352B-4B01-8765-4F4B40DF45CB}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20308674453996
+ },
+ "Name": "srcEndpoint=(Extract Properties: Out), destEndpoint=(Not Equal To (!=): In)",
+ "Components": {
+ "Component_[14597948098713219792]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 14597948098713219792,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20248544911852
+ },
+ "slotId": {
+ "m_id": "{C69C098D-D667-4DC7-85E5-AFD119727D94}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20257134846444
+ },
+ "slotId": {
+ "m_id": "{AE7E453C-15DE-47D2-954A-05C3895B7AC6}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20312969421292
+ },
+ "Name": "srcEndpoint=(Extract Properties: FwdBack: Number), destEndpoint=(Not Equal To (!=): Value A)",
+ "Components": {
+ "Component_[14915522756837814768]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 14915522756837814768,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20248544911852
+ },
+ "slotId": {
+ "m_id": "{0C03D491-DE25-46C2-BF09-14769FA49FDB}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20257134846444
+ },
+ "slotId": {
+ "m_id": "{57EBC15B-452E-49B3-8BD3-4FBBB07F1F14}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20317264388588
+ },
+ "Name": "srcEndpoint=(Extract Properties: Out), destEndpoint=(Not Equal To (!=): In)",
+ "Components": {
+ "Component_[6510282773353837676]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 6510282773353837676,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20248544911852
+ },
+ "slotId": {
+ "m_id": "{C69C098D-D667-4DC7-85E5-AFD119727D94}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20265724781036
+ },
+ "slotId": {
+ "m_id": "{AE7E453C-15DE-47D2-954A-05C3895B7AC6}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20321559355884
+ },
+ "Name": "srcEndpoint=(Extract Properties: LeftRight: Number), destEndpoint=(Not Equal To (!=): Value A)",
+ "Components": {
+ "Component_[16150645152204311425]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 16150645152204311425,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20248544911852
+ },
+ "slotId": {
+ "m_id": "{4C13F9EF-60BF-4AD1-8FA9-66F46455411C}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20265724781036
+ },
+ "slotId": {
+ "m_id": "{57EBC15B-452E-49B3-8BD3-4FBBB07F1F14}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20325854323180
+ },
+ "Name": "srcEndpoint=(Not Equal To (!=): True), destEndpoint=(Print: In)",
+ "Components": {
+ "Component_[3322355580364572639]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 3322355580364572639,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20257134846444
+ },
+ "slotId": {
+ "m_id": "{AC364E17-A9A1-42DB-A29D-7B2D666E4287}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20270019748332
+ },
+ "slotId": {
+ "m_id": "{733AA75D-022C-45E9-9D0F-3EF9A1633ADC}"
+ }
+ }
+ }
+ }
+ },
+ {
+ "Id": {
+ "id": 20330149290476
+ },
+ "Name": "srcEndpoint=(Not Equal To (!=): True), destEndpoint=(Print: In)",
+ "Components": {
+ "Component_[1975626970668030308]": {
+ "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
+ "Id": 1975626970668030308,
+ "sourceEndpoint": {
+ "nodeId": {
+ "id": 20265724781036
+ },
+ "slotId": {
+ "m_id": "{AC364E17-A9A1-42DB-A29D-7B2D666E4287}"
+ }
+ },
+ "targetEndpoint": {
+ "nodeId": {
+ "id": 20274314715628
+ },
+ "slotId": {
+ "m_id": "{733AA75D-022C-45E9-9D0F-3EF9A1633ADC}"
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "m_assetType": "{3E2AC8CD-713F-453E-967F-29517F331784}",
+ "versionData": {
+ "_grammarVersion": 1,
+ "_runtimeVersion": 1,
+ "_fileVersion": 1
+ },
+ "m_variableCounter": 2,
+ "GraphCanvasData": [
+ {
+ "Key": {
+ "id": 20239954977260
+ },
+ "Value": {
+ "ComponentData": {
+ "{5F84B500-8C45-40D1-8EFC-A5306B241444}": {
+ "$type": "SceneComponentSaveData",
+ "ViewParams": {
+ "Scale": 1.0097068678919363,
+ "AnchorX": 1086.4539794921875,
+ "AnchorY": 198.07728576660156
+ }
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20244249944556
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "MethodNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 740.0,
+ 100.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData",
+ "SubStyle": ".method"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{7A7C96CB-4B5A-48DD-A0AD-0094A113549B}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20248544911852
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "DefaultNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 740.0,
+ 320.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{ED8F0B6C-0811-4FB7-AEE8-B71DB87FABF0}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20252839879148
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 160.0,
+ 100.0
+ ]
+ },
+ "{9E81C95F-89C0-4476-8E82-63CCC4E52E04}": {
+ "$type": "EBusHandlerNodeDescriptorSaveData",
+ "EventIds": [
+ {
+ "Value": 78438309
+ },
+ {
+ "Value": 1793364217
+ }
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{BB97BA3E-F2AB-4078-9BB3-2A0F31DC771C}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20257134846444
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "MathNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 1040.0,
+ 320.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{71AB4748-41F4-4FEA-874C-F54037236F31}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20261429813740
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "StringNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 740.0,
+ -100.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{26E363EE-F35A-4096-88EF-DF907A809894}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20265724781036
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "MathNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 1040.0,
+ 520.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{F64E211C-8DDD-4223-9235-8DB802A017CB}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20270019748332
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "StringNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 1480.0,
+ 320.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{9161B9FA-8493-479D-BE35-10D92644D5C0}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20274314715628
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "StringNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 1480.0,
+ 520.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{1AF129A6-751C-4FC0-805E-65AC2D4B6D3D}"
+ }
+ }
+ }
+ },
+ {
+ "Key": {
+ "id": 20278609682924
+ },
+ "Value": {
+ "ComponentData": {
+ "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
+ "$type": "NodeSaveData"
+ },
+ "{328FF15C-C302-458F-A43D-E1794DE0904E}": {
+ "$type": "GeneralNodeTitleComponentSaveData",
+ "PaletteOverride": "StringNodeTitlePalette"
+ },
+ "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
+ "$type": "GeometrySaveData",
+ "Position": [
+ 740.0,
+ 740.0
+ ]
+ },
+ "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
+ "$type": "StylingComponentSaveData"
+ },
+ "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
+ "$type": "PersistentIdComponentSaveData",
+ "PersistentId": "{F7407B9B-C302-4B50-BFB0-D1208DF1D5AC}"
+ }
+ }
+ }
+ }
+ ],
+ "StatisticsHelper": {
+ "InstanceCounter": [
+ {
+ "Key": 5842116704436214676,
+ "Value": 1
+ },
+ {
+ "Key": 5842116706017748280,
+ "Value": 1
+ },
+ {
+ "Key": 7441100700879769985,
+ "Value": 2
+ },
+ {
+ "Key": 10684225535275896474,
+ "Value": 4
+ },
+ {
+ "Key": 10715014621082578046,
+ "Value": 1
+ },
+ {
+ "Key": 14285852892804039565,
+ "Value": 1
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/Player.prefab b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/Player.prefab
new file mode 100644
index 0000000000..72fce2d291
--- /dev/null
+++ b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/Player.prefab
@@ -0,0 +1,196 @@
+{
+ "ContainerEntity": {
+ "Id": "ContainerEntity",
+ "Name": "Player",
+ "Components": {
+ "Component_[10591405285626521927]": {
+ "$type": "EditorLockComponent",
+ "Id": 10591405285626521927
+ },
+ "Component_[10962884071806037909]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 10962884071806037909,
+ "Parent Entity": ""
+ },
+ "Component_[14883697413991420474]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 14883697413991420474
+ },
+ "Component_[1497622121956209837]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 1497622121956209837
+ },
+ "Component_[16429314387772079347]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 16429314387772079347
+ },
+ "Component_[16665294301093657382]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 16665294301093657382
+ },
+ "Component_[1706666252612720326]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 1706666252612720326
+ },
+ "Component_[4216896820422195198]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 4216896820422195198
+ },
+ "Component_[4540089401187370610]": {
+ "$type": "EditorPrefabComponent",
+ "Id": 4540089401187370610
+ },
+ "Component_[6378576046601184103]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 6378576046601184103
+ },
+ "Component_[7745420981568587180]": {
+ "$type": "SelectionComponent",
+ "Id": 7745420981568587180
+ }
+ }
+ },
+ "Entities": {
+ "Entity_[1028733630164]": {
+ "Id": "Entity_[1028733630164]",
+ "Name": "Player",
+ "Components": {
+ "Component_[12294726333564087591]": {
+ "$type": "SelectionComponent",
+ "Id": 12294726333564087591
+ },
+ "Component_[13587084088242540786]": {
+ "$type": "EditorInspectorComponent",
+ "Id": 13587084088242540786,
+ "ComponentOrderEntryArray": [
+ {
+ "ComponentId": 6819443882832501114
+ },
+ {
+ "ComponentId": 5577505593558922067,
+ "SortIndex": 1
+ },
+ {
+ "ComponentId": 2069554278758260821,
+ "SortIndex": 2
+ },
+ {
+ "ComponentId": 16508969730014660362,
+ "SortIndex": 3
+ },
+ {
+ "ComponentId": 8125406152674415588,
+ "SortIndex": 4
+ },
+ {
+ "ComponentId": 4337571454344109612,
+ "SortIndex": 5
+ },
+ {
+ "ComponentId": 16457408099527309065,
+ "SortIndex": 6
+ }
+ ]
+ },
+ "Component_[14335168881008289852]": {
+ "$type": "EditorEntitySortComponent",
+ "Id": 14335168881008289852
+ },
+ "Component_[16308902899170829847]": {
+ "$type": "EditorVisibilityComponent",
+ "Id": 16308902899170829847
+ },
+ "Component_[16457408099527309065]": {
+ "$type": "GenericComponentWrapper",
+ "Id": 16457408099527309065,
+ "m_template": {
+ "$type": "Multiplayer::NetworkTransformComponent"
+ }
+ },
+ "Component_[16508969730014660362]": {
+ "$type": "GenericComponentWrapper",
+ "Id": 16508969730014660362,
+ "m_template": {
+ "$type": "AutomatedTesting::NetworkTestPlayerComponent"
+ }
+ },
+ "Component_[16541569566865026527]": {
+ "$type": "EditorOnlyEntityComponent",
+ "Id": 16541569566865026527
+ },
+ "Component_[2002761223483048905]": {
+ "$type": "EditorPendingCompositionComponent",
+ "Id": 2002761223483048905
+ },
+ "Component_[2069554278758260821]": {
+ "$type": "EditorScriptCanvasComponent",
+ "Id": 2069554278758260821,
+ "m_name": "AutoComponent_NetworkInput",
+ "m_assetHolder": {
+ "m_asset": {
+ "assetId": {
+ "guid": "{D079F53D-CCAA-5C98-8E0C-B485B7821747}"
+ },
+ "assetHint": "levels/multiplayer/autocomponent_networkinput/autocomponent_networkinput.scriptcanvas"
+ }
+ },
+ "runtimeDataIsValid": true,
+ "runtimeDataOverrides": {
+ "source": {
+ "assetId": {
+ "guid": "{D079F53D-CCAA-5C98-8E0C-B485B7821747}"
+ },
+ "assetHint": "levels/multiplayer/autocomponent_networkinput/autocomponent_networkinput.scriptcanvas"
+ }
+ }
+ },
+ "Component_[4337571454344109612]": {
+ "$type": "GenericComponentWrapper",
+ "Id": 4337571454344109612,
+ "m_template": {
+ "$type": "NetBindComponent"
+ }
+ },
+ "Component_[477591477979440744]": {
+ "$type": "EditorLockComponent",
+ "Id": 477591477979440744
+ },
+ "Component_[5577505593558922067]": {
+ "$type": "AZ::Render::EditorMeshComponent",
+ "Id": 5577505593558922067,
+ "Controller": {
+ "Configuration": {
+ "ModelAsset": {
+ "assetId": {
+ "guid": "{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}",
+ "subId": 284780167
+ },
+ "assetHint": "models/sphere.azmodel"
+ }
+ }
+ }
+ },
+ "Component_[5828214869455694702]": {
+ "$type": "EditorDisabledCompositionComponent",
+ "Id": 5828214869455694702
+ },
+ "Component_[6819443882832501114]": {
+ "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
+ "Id": 6819443882832501114,
+ "Parent Entity": "ContainerEntity"
+ },
+ "Component_[8125406152674415588]": {
+ "$type": "GenericComponentWrapper",
+ "Id": 8125406152674415588,
+ "m_template": {
+ "$type": "Multiplayer::LocalPredictionPlayerInputComponent"
+ }
+ },
+ "Component_[8838623765985560328]": {
+ "$type": "EditorEntityIconComponent",
+ "Id": 8838623765985560328
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/tags.txt b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/tags.txt
new file mode 100644
index 0000000000..0d6c1880e7
--- /dev/null
+++ b/AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/tags.txt
@@ -0,0 +1,12 @@
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
diff --git a/AutomatedTesting/Passes/MainPipeline.pass b/AutomatedTesting/Passes/MainPipeline.pass
index aa9f3757c4..c34c556983 100644
--- a/AutomatedTesting/Passes/MainPipeline.pass
+++ b/AutomatedTesting/Passes/MainPipeline.pass
@@ -205,6 +205,99 @@
}
]
},
+
+ {
+ // NOTE: HairParentPass does not write into Depth MSAA from Opaque Pass. If new passes downstream
+ // of HairParentPass will need to use Depth MSAA, HairParentPass will need to be updated to use Depth MSAA
+ // instead of regular Depth as DepthStencil. Specifically, HairResolvePPLL.pass and the associated
+ // .azsl file will need to be updated.
+ "Name": "HairParentPass",
+ // Note: The following two lines represent the choice of rendering pipeline for the hair.
+ // You can either choose to use PPLL or ShortCut and accordingly change the flag
+ // 'm_usePPLLRenderTechnique' in the class 'HairFeatureProcessor.cpp'
+// "TemplateName": "HairParentPassTemplate",
+ "TemplateName": "HairParentShortCutPassTemplate",
+ "Enabled": true,
+ "Connections": [
+ // Critical to keep DepthLinear as input - used to set the size of the Head PPLL image buffer.
+ // If DepthLinear is not available - connect to another viewport (non MSAA) image.
+ {
+ "LocalSlot": "DepthLinearInput",
+ "AttachmentRef": {
+ "Pass": "DepthPrePass",
+ "Attachment": "DepthLinear"
+ }
+ },
+ {
+ "LocalSlot": "Depth",
+ "AttachmentRef": {
+ "Pass": "DepthPrePass",
+ "Attachment": "Depth"
+ }
+ },
+ {
+ "LocalSlot": "RenderTargetInputOutput",
+ "AttachmentRef": {
+ "Pass": "OpaquePass",
+ "Attachment": "Output"
+ }
+ },
+ {
+ "LocalSlot": "RenderTargetInputOnly",
+ "AttachmentRef": {
+ "Pass": "OpaquePass",
+ "Attachment": "Output"
+ }
+ },
+
+ // Shadows resources
+ {
+ "LocalSlot": "DirectionalShadowmap",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "DirectionalShadowmap"
+ }
+ },
+ {
+ "LocalSlot": "DirectionalESM",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "DirectionalESM"
+ }
+ },
+ {
+ "LocalSlot": "ProjectedShadowmap",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "ProjectedShadowmap"
+ }
+ },
+ {
+ "LocalSlot": "ProjectedESM",
+ "AttachmentRef": {
+ "Pass": "ShadowPass",
+ "Attachment": "ProjectedESM"
+ }
+ },
+
+ // Lighting Resources
+ {
+ "LocalSlot": "TileLightData",
+ "AttachmentRef": {
+ "Pass": "LightCullingPass",
+ "Attachment": "TileLightData"
+ }
+ },
+ {
+ "LocalSlot": "LightListRemapped",
+ "AttachmentRef": {
+ "Pass": "LightCullingPass",
+ "Attachment": "LightListRemapped"
+ }
+ }
+ ]
+ },
+
{
"Name": "TransparentPass",
"TemplateName": "TransparentParentTemplate",
@@ -254,22 +347,22 @@
{
"LocalSlot": "InputLinearDepth",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "DepthStencil",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "InputOutput",
"AttachmentRef": {
- "Pass": "OpaquePass",
- "Attachment": "Output"
+ "Pass": "HairParentPass",
+ "Attachment": "RenderTargetInputOutput"
}
}
]
@@ -282,22 +375,22 @@
{
"LocalSlot": "InputLinearDepth",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "DepthLinear"
}
},
{
"LocalSlot": "InputDepthStencil",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "Depth"
}
},
{
"LocalSlot": "RenderTargetInputOutput",
"AttachmentRef": {
- "Pass": "TransparentPass",
- "Attachment": "InputOutput"
+ "Pass": "HairParentPass",
+ "Attachment": "RenderTargetInputOutput"
}
}
],
@@ -337,7 +430,7 @@
{
"LocalSlot": "Depth",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "Depth"
}
},
@@ -372,7 +465,7 @@
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "Depth"
}
}
@@ -431,7 +524,7 @@
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "Depth"
}
}
@@ -451,7 +544,7 @@
{
"LocalSlot": "DepthInputOutput",
"AttachmentRef": {
- "Pass": "DepthPrePass",
+ "Pass": "HairParentPass",
"Attachment": "Depth"
}
}
diff --git a/Code/Editor/CVarMenu.h b/Code/Editor/CVarMenu.h
index efcc8e8caf..5195bd99d7 100644
--- a/Code/Editor/CVarMenu.h
+++ b/Code/Editor/CVarMenu.h
@@ -16,9 +16,12 @@
#include
#include
+struct ICVar;
+
class CVarMenu
: public QMenu
{
+ Q_OBJECT
public:
// CVar that can be toggled on and off
struct CVarToggle
diff --git a/Code/Editor/ConfigGroup.cpp b/Code/Editor/ConfigGroup.cpp
index 74fe6f7b5c..42236e43dd 100644
--- a/Code/Editor/ConfigGroup.cpp
+++ b/Code/Editor/ConfigGroup.cpp
@@ -19,10 +19,9 @@ namespace Config
CConfigGroup::~CConfigGroup()
{
- for (TConfigVariables::const_iterator it = m_vars.begin();
- it != m_vars.end(); ++it)
+ for (IConfigVar* var : m_vars)
{
- delete (*it);
+ delete var;
}
}
@@ -31,17 +30,15 @@ namespace Config
m_vars.push_back(var);
}
- uint32 CConfigGroup::GetVarCount()
+ AZ::u32 CConfigGroup::GetVarCount()
{
- return static_cast(m_vars.size());
+ return aznumeric_cast(m_vars.size());
}
IConfigVar* CConfigGroup::GetVar(const char* szName)
{
- for (TConfigVariables::const_iterator it = m_vars.begin();
- it != m_vars.end(); ++it)
+ for (IConfigVar* var : m_vars)
{
- IConfigVar* var = (*it);
if (0 == _stricmp(szName, var->GetName().c_str()))
{
return var;
@@ -53,20 +50,19 @@ namespace Config
const IConfigVar* CConfigGroup::GetVar(const char* szName) const
{
- for (TConfigVariables::const_iterator it = m_vars.begin();
- it != m_vars.end(); ++it)
+ for (const IConfigVar* var : m_vars)
{
- IConfigVar* var = (*it);
if (0 == _stricmp(szName, var->GetName().c_str()))
{
return var;
}
+
}
return nullptr;
}
- IConfigVar* CConfigGroup::GetVar(uint index)
+ IConfigVar* CConfigGroup::GetVar(AZ::u32 index)
{
if (index < m_vars.size())
{
@@ -76,7 +72,7 @@ namespace Config
return nullptr;
}
- const IConfigVar* CConfigGroup::GetVar(uint index) const
+ const IConfigVar* CConfigGroup::GetVar(AZ::u32 index) const
{
if (index < m_vars.size())
{
@@ -89,114 +85,110 @@ namespace Config
void CConfigGroup::SaveToXML(XmlNodeRef node)
{
// save only values that don't have default values
- for (TConfigVariables::const_iterator it = m_vars.begin();
- it != m_vars.end(); ++it)
+ for (const IConfigVar* var : m_vars)
{
- IConfigVar* var = (*it);
- if (!var->IsFlagSet(IConfigVar::eFlag_DoNotSave))
+ if (var->IsFlagSet(IConfigVar::eFlag_DoNotSave) || var->IsDefault())
{
- if (!var->IsDefault())
- {
- const char* szName = var->GetName().c_str();
+ continue;
+ }
- switch (var->GetType())
- {
- case IConfigVar::eType_BOOL:
- {
- bool currentValue = false;
- var->Get(¤tValue);
- node->setAttr(szName, currentValue);
- break;
- }
+ const char* szName = var->GetName().c_str();
- case IConfigVar::eType_INT:
- {
- int currentValue = 0;
- var->Get(¤tValue);
- node->setAttr(szName, currentValue);
- break;
- }
+ switch (var->GetType())
+ {
+ case IConfigVar::eType_BOOL:
+ {
+ bool currentValue = false;
+ var->Get(¤tValue);
+ node->setAttr(szName, currentValue);
+ break;
+ }
- case IConfigVar::eType_FLOAT:
- {
- float currentValue = 0;
- var->Get(¤tValue);
- node->setAttr(szName, currentValue);
- break;
- }
+ case IConfigVar::eType_INT:
+ {
+ int currentValue = 0;
+ var->Get(¤tValue);
+ node->setAttr(szName, currentValue);
+ break;
+ }
- case IConfigVar::eType_STRING:
- {
- AZStd::string currentValue;
- var->Get(¤tValue);
- node->setAttr(szName, currentValue.c_str());
- break;
- }
- }
- }
+ case IConfigVar::eType_FLOAT:
+ {
+ float currentValue = 0;
+ var->Get(¤tValue);
+ node->setAttr(szName, currentValue);
+ break;
+ }
+
+ case IConfigVar::eType_STRING:
+ {
+ AZStd::string currentValue;
+ var->Get(¤tValue);
+ node->setAttr(szName, currentValue.c_str());
+ break;
+ }
}
}
}
void CConfigGroup::LoadFromXML(XmlNodeRef node)
{
- // save only values that don't have default values
- for (TConfigVariables::const_iterator it = m_vars.begin();
- it != m_vars.end(); ++it)
+ // load values that are save-able
+ for (IConfigVar* var : m_vars)
{
- IConfigVar* var = (*it);
- if (!var->IsFlagSet(IConfigVar::eFlag_DoNotSave))
+ if (var->IsFlagSet(IConfigVar::eFlag_DoNotSave))
{
- const char* szName = var->GetName().c_str();
+ continue;
+ }
+ const char* szName = var->GetName().c_str();
- switch (var->GetType())
+ switch (var->GetType())
+ {
+ case IConfigVar::eType_BOOL:
+ {
+ bool currentValue = false;
+ var->GetDefault(¤tValue);
+ if (node->getAttr(szName, currentValue))
{
- case IConfigVar::eType_BOOL:
- {
- bool currentValue = false;
- var->GetDefault(¤tValue);
- if (node->getAttr(szName, currentValue))
- {
- var->Set(¤tValue);
- }
- break;
+ var->Set(¤tValue);
}
+ break;
+ }
- case IConfigVar::eType_INT:
+ case IConfigVar::eType_INT:
+ {
+ int currentValue = 0;
+ var->GetDefault(¤tValue);
+ if (node->getAttr(szName, currentValue))
{
- int currentValue = 0;
- var->GetDefault(¤tValue);
- if (node->getAttr(szName, currentValue))
- {
- var->Set(¤tValue);
- }
- break;
+ var->Set(¤tValue);
}
+ break;
+ }
- case IConfigVar::eType_FLOAT:
+ case IConfigVar::eType_FLOAT:
+ {
+ float currentValue = 0;
+ var->GetDefault(¤tValue);
+ if (node->getAttr(szName, currentValue))
{
- float currentValue = 0;
- var->GetDefault(¤tValue);
- if (node->getAttr(szName, currentValue))
- {
- var->Set(¤tValue);
- }
- break;
+ var->Set(¤tValue);
}
+ break;
+ }
- case IConfigVar::eType_STRING:
+ case IConfigVar::eType_STRING:
+ {
+ AZStd::string currentValue;
+ var->GetDefault(¤tValue);
+ QString readValue(currentValue.c_str());
+ if (node->getAttr(szName, readValue))
{
- AZStd::string currentValue;
- var->GetDefault(¤tValue);
- QString readValue(currentValue.c_str());
- if (node->getAttr(szName, readValue))
- {
- currentValue = readValue.toUtf8().data();
- var->Set(¤tValue);
- }
- break;
- }
+ currentValue = readValue.toUtf8().data();
+ var->Set(¤tValue);
}
+ break;
+ }
}
}
}
diff --git a/Code/Editor/ConfigGroup.h b/Code/Editor/ConfigGroup.h
index 769a29ba8a..004725e32c 100644
--- a/Code/Editor/ConfigGroup.h
+++ b/Code/Editor/ConfigGroup.h
@@ -8,8 +8,12 @@
#pragma once
-#ifndef CRYINCLUDE_EDITOR_CONFIGGROUP_H
-#define CRYINCLUDE_EDITOR_CONFIGGROUP_H
+#include
+#include
+#include
+
+struct ICVar;
+class XmlNodeRef;
namespace Config
{
@@ -32,7 +36,7 @@ namespace Config
eFlag_DoNotSave = 1 << 2,
};
- IConfigVar(const char* szName, const char* szDescription, EType varType, uint8 flags)
+ IConfigVar(const char* szName, const char* szDescription, EType varType, AZ::u8 flags)
: m_name(szName)
, m_description(szDescription)
, m_type(varType)
@@ -42,22 +46,22 @@ namespace Config
virtual ~IConfigVar() = default;
- ILINE EType GetType() const
+ AZ_FORCE_INLINE EType GetType() const
{
return m_type;
}
- ILINE const AZStd::string& GetName() const
+ AZ_FORCE_INLINE const AZStd::string& GetName() const
{
return m_name;
}
- ILINE const AZStd::string& GetDescription() const
+ AZ_FORCE_INLINE const AZStd::string& GetDescription() const
{
return m_description;
}
- ILINE bool IsFlagSet(EFlags flag) const
+ AZ_FORCE_INLINE bool IsFlagSet(EFlags flag) const
{
return 0 != (m_flags & flag);
}
@@ -68,73 +72,28 @@ namespace Config
virtual void GetDefault(void* outPtr) const = 0;
virtual void Reset() = 0;
- static EType TranslateType(const bool&) { return eType_BOOL; }
- static EType TranslateType(const int&) { return eType_INT; }
- static EType TranslateType(const float&) { return eType_FLOAT; }
- static EType TranslateType(const AZStd::string&) { return eType_STRING; }
+ static constexpr EType TranslateType(const bool&) { return eType_BOOL; }
+ static constexpr EType TranslateType(const int&) { return eType_INT; }
+ static constexpr EType TranslateType(const float&) { return eType_FLOAT; }
+ static constexpr EType TranslateType(const AZStd::string&) { return eType_STRING; }
protected:
EType m_type;
- uint8 m_flags;
+ AZ::u8 m_flags;
AZStd::string m_name;
AZStd::string m_description;
void* m_ptr;
ICVar* m_pCVar;
};
- // Typed wrapper for config variable
- template
- class TConfigVar
- : public IConfigVar
- {
- private:
- T m_default;
-
- public:
- TConfigVar(const char* szName, const char* szDescription, uint8 flags, T& ptr, const T& defaultValue)
- : IConfigVar(szName, szDescription, IConfigVar::TranslateType(ptr), flags)
- , m_default(defaultValue)
- {
- m_ptr = &ptr;
-
- // reset to default value on initializations
- ptr = defaultValue;
- }
-
- virtual void Get(void* outPtr) const
- {
- *reinterpret_cast(outPtr) = *reinterpret_cast(m_ptr);
- }
-
- virtual void Set(const void* ptr)
- {
- *reinterpret_cast(m_ptr) = *reinterpret_cast(ptr);
- }
-
- virtual void Reset()
- {
- *reinterpret_cast(m_ptr) = m_default;
- }
-
- virtual void GetDefault(void* outPtr) const
- {
- *reinterpret_cast(outPtr) = m_default;
- }
-
- virtual bool IsDefault() const
- {
- return *reinterpret_cast(m_ptr) == m_default;
- }
- };
-
// Group of configuration variables with optional mapping to CVars
class CConfigGroup
{
private:
- typedef std::vector TConfigVariables;
+ using TConfigVariables = AZStd::vector ;
TConfigVariables m_vars;
- typedef std::vector TConsoleVariables;
+ using TConsoleVariables = AZStd::vector;
TConsoleVariables m_consoleVars;
public:
@@ -142,20 +101,13 @@ namespace Config
virtual ~CConfigGroup();
void AddVar(IConfigVar* var);
- uint32 GetVarCount();
+ AZ::u32 GetVarCount();
IConfigVar* GetVar(const char* szName);
- IConfigVar* GetVar(uint index);
+ IConfigVar* GetVar(AZ::u32 index);
const IConfigVar* GetVar(const char* szName) const;
- const IConfigVar* GetVar(uint index) const;
+ const IConfigVar* GetVar(AZ::u32 index) const;
void SaveToXML(XmlNodeRef node);
void LoadFromXML(XmlNodeRef node);
-
- template
- void AddVar(const char* szName, const char* szDescription, T& var, const T& defaultValue, uint8 flags = 0)
- {
- AddVar(new TConfigVar(szName, szDescription, flags, var, defaultValue));
- }
};
};
-#endif // CRYINCLUDE_EDITOR_CONFIGGROUP_H
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h
index 5ec24b679d..849e44cedd 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h
+++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyMiscCtrl.h
@@ -6,8 +6,6 @@
*
*/
-#ifndef CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H
-#define CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H
#pragma once
#if !defined(Q_MOC_RUN)
@@ -53,6 +51,7 @@ private:
class UserPopupWidgetHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarUser, UserPropertyEditor>
{
+ Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(UserPopupWidgetHandler, AZ::SystemAllocator, 0);
bool IsDefaultHandler() const override { return false; }
@@ -67,6 +66,7 @@ public:
class FloatCurveHandler : public QObject, public AzToolsFramework::PropertyHandler < CReflectedVarSpline, CSplineCtrl>
{
+ Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(FloatCurveHandler, AZ::SystemAllocator, 0);
bool IsDefaultHandler() const override { return false; }
@@ -80,5 +80,3 @@ public:
void OnSplineChange(CSplineCtrl*);
};
-
-#endif // CRYINCLUDE_EDITOR_UTILS_PROPERTYMISCCTRL_H
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp
index c5ccc599d6..d26e978ae8 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp
+++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.cpp
@@ -58,17 +58,9 @@ private:
void OnClicked() override
{
QString tempValue("");
- QString ext("");
- if (m_path.isEmpty() == false)
+ if (!m_path.isEmpty() && !Path::GetExt(m_path).isEmpty())
{
- if (Path::GetExt(m_path) == "")
- {
- tempValue = "";
- }
- else
- {
- tempValue = m_path;
- }
+ tempValue = m_path;
}
AssetSelectionModel selection;
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h
index fa30eba034..087ee9f1db 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h
+++ b/Code/Editor/Controls/ReflectedPropertyControl/PropertyResourceCtrl.h
@@ -99,6 +99,7 @@ class FileResourceSelectorWidgetHandler
: QObject
, public AzToolsFramework::PropertyHandler < CReflectedVarResource, FileResourceSelectorWidget >
{
+ Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(FileResourceSelectorWidgetHandler, AZ::SystemAllocator, 0);
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp
index b3f1b35461..2320938f08 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp
+++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVarWrapper.cpp
@@ -446,41 +446,54 @@ void ReflectedVarUserAdapter::SetVariable(IVariable *pVariable)
m_reflectedVar.reset(new CReflectedVarUser( pVariable->GetHumanName().toUtf8().data()));
}
-void ReflectedVarUserAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
+void ReflectedVarUserAdapter::SyncReflectedVarToIVar(IVariable* pVariable)
{
QString value;
pVariable->Get(value);
m_reflectedVar->m_value = value.toUtf8().data();
- //extract the list of custom items from the IVariable user data
- IVariable::IGetCustomItems* pGetCustomItems = static_cast (pVariable->GetUserData().value());
- if (pGetCustomItems != nullptr)
- {
- std::vector items;
- QString dlgTitle;
- // call the user supplied callback to fill-in items and get dialog title
- bool bShowIt = pGetCustomItems->GetItems(pVariable, items, dlgTitle);
- if (bShowIt) // if func didn't veto, show the dialog
- {
- m_reflectedVar->m_enableEdit = true;
- m_reflectedVar->m_useTree = pGetCustomItems->UseTree();
- m_reflectedVar->m_treeSeparator = pGetCustomItems->GetTreeSeparator();
- m_reflectedVar->m_dialogTitle = dlgTitle.toUtf8().data();
- m_reflectedVar->m_itemNames.resize(items.size());
- m_reflectedVar->m_itemDescriptions.resize(items.size());
-
- QByteArray ba;
- int i = -1;
- std::generate(m_reflectedVar->m_itemNames.begin(), m_reflectedVar->m_itemNames.end(), [&items, &i, &ba]() { ++i; ba = items[i].name.toUtf8(); return ba.data(); });
- i = -1;
- std::generate(m_reflectedVar->m_itemDescriptions.begin(), m_reflectedVar->m_itemDescriptions.end(), [&items, &i, &ba]() { ++i; ba = items[i].desc.toUtf8(); return ba.data(); });
-
- }
- }
- else
+ // extract the list of custom items from the IVariable user data
+ IVariable::IGetCustomItems* pGetCustomItems = static_cast(pVariable->GetUserData().value());
+ if (pGetCustomItems == nullptr)
{
m_reflectedVar->m_enableEdit = false;
+ return;
}
+
+ std::vector items;
+ QString dlgTitle;
+ // call the user supplied callback to fill-in items and get dialog title
+ bool bShowIt = pGetCustomItems->GetItems(pVariable, items, dlgTitle);
+ if (!bShowIt) // if func vetoed it, don't show the dialog
+ {
+ return;
+ }
+ m_reflectedVar->m_enableEdit = true;
+ m_reflectedVar->m_useTree = pGetCustomItems->UseTree();
+ m_reflectedVar->m_treeSeparator = pGetCustomItems->GetTreeSeparator();
+ m_reflectedVar->m_dialogTitle = dlgTitle.toUtf8().data();
+ m_reflectedVar->m_itemNames.resize(items.size());
+ m_reflectedVar->m_itemDescriptions.resize(items.size());
+
+ QByteArray ba;
+ int i = -1;
+ AZStd::generate(
+ m_reflectedVar->m_itemNames.begin(), m_reflectedVar->m_itemNames.end(),
+ [&items, &i, &ba]()
+ {
+ ++i;
+ ba = items[i].name.toUtf8();
+ return ba.data();
+ });
+ i = -1;
+ AZStd::generate(
+ m_reflectedVar->m_itemDescriptions.begin(), m_reflectedVar->m_itemDescriptions.end(),
+ [&items, &i, &ba]()
+ {
+ ++i;
+ ba = items[i].desc.toUtf8();
+ return ba.data();
+ });
}
void ReflectedVarUserAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
diff --git a/Code/Editor/Controls/TimelineCtrl.cpp b/Code/Editor/Controls/TimelineCtrl.cpp
index aa30c326ac..3890b46b2b 100644
--- a/Code/Editor/Controls/TimelineCtrl.cpp
+++ b/Code/Editor/Controls/TimelineCtrl.cpp
@@ -126,7 +126,6 @@ void TimelineWidget::DrawTicks(QPainter* painter)
const QPen pOldPen = painter->pen();
const QPen ltgray(QColor(110, 110, 110));
- const QPen black(palette().color(QPalette::Normal, QPalette::Text));
const QPen redpen(QColor(255, 0, 255));
// Draw time ticks every tick step seconds.
@@ -598,7 +597,6 @@ void TimelineWidget::DrawSecondTicks(QPainter* painter)
{
const QPen ltgray(QColor(110, 110, 110));
const QPen black(palette().color(QPalette::Normal, QPalette::Text));
- const QPen redpen(QColor(255, 0, 255));
for (int gx = m_grid.firstGridLine.x(); gx < m_grid.firstGridLine.x() + m_grid.numGridLines.x() + 1; gx++)
{
diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp
index fdde1ac305..70aff10f87 100644
--- a/Code/Editor/Core/LevelEditorMenuHandler.cpp
+++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp
@@ -832,7 +832,7 @@ QAction* LevelEditorMenuHandler::CreateViewPaneAction(const QtViewPane* view)
if (view->m_options.showOnToolsToolbar)
{
- action->setIcon(QIcon(view->m_options.toolbarIcon));
+ action->setIcon(QIcon(view->m_options.toolbarIcon.c_str()));
}
m_actionManager->AddAction(view->m_id, action);
diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp
index e4138da932..b47febd5ed 100644
--- a/Code/Editor/CryEdit.cpp
+++ b/Code/Editor/CryEdit.cpp
@@ -45,6 +45,7 @@ AZ_POP_DISABLE_WARNING
// AzCore
#include
+#include
#include
#include
#include
@@ -547,7 +548,6 @@ public:
{ "BatchMode", m_bConsoleMode },
{ "NullRenderer", m_bNullRenderer },
{ "devmode", m_bDeveloperMode },
- { "VTUNE", dummy },
{ "runpython", m_bRunPythonScript },
{ "runpythontest", m_bRunPythonTestScript },
{ "version", m_bShowVersionInfo },
@@ -1686,6 +1686,11 @@ bool CCryEditApp::InitInstance()
return false;
}
+ if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get())
+ {
+ AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "LegacySystemInterfaceCreated", R"({})");
+ }
+
// Process some queued events come from system init
// Such as asset catalog loaded notification.
// There are some systems need to load configurations from assets for post initialization but before loading level
@@ -4137,7 +4142,15 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware);
Editor::EditorQtApplication* app = Editor::EditorQtApplication::newInstance(argc, argv);
- if (app->arguments().contains("-autotest_mode"))
+ QStringList qArgs = app->arguments();
+ const bool is_automated_test = AZStd::any_of(qArgs.begin(), qArgs.end(),
+ [](const QString& elem)
+ {
+ return elem.endsWith("autotest_mode") || elem.endsWith("runpythontest");
+ }
+ );
+
+ if (is_automated_test)
{
// Nullroute all stdout to null for automated tests, this way we make sure
// that the test result output is not polluted with unrelated output data.
diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h
index f68cfdc33d..53ee8f1905 100644
--- a/Code/Editor/CryEdit.h
+++ b/Code/Editor/CryEdit.h
@@ -431,6 +431,7 @@ public:
class CCrySingleDocTemplate
: public QObject
{
+ Q_OBJECT
private:
explicit CCrySingleDocTemplate(const QMetaObject* pDocClass)
: QObject()
diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp
index 4944c3bff5..212606c737 100644
--- a/Code/Editor/CryEditDoc.cpp
+++ b/Code/Editor/CryEditDoc.cpp
@@ -60,15 +60,6 @@
#include
#include // for LmbrCentral::EditorLightComponentRequestBus
-//#define PROFILE_LOADING_WITH_VTUNE
-
-// profilers api.
-//#include "pure.h"
-#ifdef PROFILE_LOADING_WITH_VTUNE
-#include "C:\Program Files\Intel\Vtune\Analyzer\Include\VTuneApi.h"
-#pragma comment(lib,"C:\\Program Files\\Intel\\Vtune\\Analyzer\\Lib\\VTuneApi.lib")
-#endif
-
static const char* kAutoBackupFolder = "_autobackup";
static const char* kHoldFolder = "$tmp_hold"; // conform to the ignored file types $tmp[0-9]*_ regex
static const char* kSaveBackupFolder = "_savebackup";
@@ -408,9 +399,6 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename)
int t0 = GetTickCount();
-#ifdef PROFILE_LOADING_WITH_VTUNE
- VTResume();
-#endif
// Load level-specific audio data.
AZStd::string levelFileName{ fileName.toUtf8().constData() };
AZStd::to_lower(levelFileName.begin(), levelFileName.end());
@@ -484,10 +472,6 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename)
CSurfaceTypeValidator().Validate();
-#ifdef PROFILE_LOADING_WITH_VTUNE
- VTPause();
-#endif
-
LogLoadTime(GetTickCount() - t0);
// Loaded with success, remove event from log file
GetIEditor()->GetSettingsManager()->UnregisterEvent(loadEvent);
diff --git a/Code/Editor/CustomResolutionDlg.h b/Code/Editor/CustomResolutionDlg.h
index 5dd9acaae8..e1b8035c65 100644
--- a/Code/Editor/CustomResolutionDlg.h
+++ b/Code/Editor/CustomResolutionDlg.h
@@ -12,8 +12,6 @@
// Notice : Refer to ViewportTitleDlg.cpp for a use case.
-#ifndef CRYINCLUDE_EDITOR_CUSTOMRESOLUTIONDLG_H
-#define CRYINCLUDE_EDITOR_CUSTOMRESOLUTIONDLG_H
#pragma once
#if !defined(Q_MOC_RUN)
@@ -28,6 +26,7 @@ namespace Ui
class CCustomResolutionDlg
: public QDialog
{
+ Q_OBJECT
public:
CCustomResolutionDlg(int w, int h, QWidget* pParent = nullptr);
~CCustomResolutionDlg();
@@ -42,5 +41,3 @@ protected:
QScopedPointer m_ui;
};
-
-#endif // CRYINCLUDE_EDITOR_CUSTOMRESOLUTIONDLG_H
diff --git a/Code/Editor/CustomizeKeyboardDialog.cpp b/Code/Editor/CustomizeKeyboardDialog.cpp
index ce09f8d878..280d6c5323 100644
--- a/Code/Editor/CustomizeKeyboardDialog.cpp
+++ b/Code/Editor/CustomizeKeyboardDialog.cpp
@@ -211,9 +211,9 @@ public:
void Reset(QAction& action)
{
- emit beginResetModel();
+ beginResetModel();
m_action = &action;
- emit endResetModel();
+ endResetModel();
}
private:
@@ -266,7 +266,7 @@ QStringList CustomizeKeyboardDialog::BuildModels(QWidget* parent)
categories.append(category);
QMenu* menu = menuAction->menu();
- m_menuActions[category] = GetAllActionsForMenu(menu, QStringLiteral(""));
+ m_menuActions[category] = GetAllActionsForMenu(menu, QString());
}
return categories;
diff --git a/Code/Editor/ErrorDialog.cpp b/Code/Editor/ErrorDialog.cpp
index 0a45b2bf89..e43df75947 100644
--- a/Code/Editor/ErrorDialog.cpp
+++ b/Code/Editor/ErrorDialog.cpp
@@ -25,9 +25,9 @@ namespace SandboxEditor
connect(m_ui->okButton, &QPushButton::clicked, this, &ErrorDialog::OnOK);
connect(
m_ui->messages,
- SIGNAL(itemSelectionChanged()),
+ &QTreeWidget::itemSelectionChanged,
this,
- SLOT(MessageSelectionChanged()));
+ &ErrorDialog::MessageSelectionChanged);
}
ErrorDialog::~ErrorDialog()
diff --git a/Code/Editor/KeyboardCustomizationSettings.cpp b/Code/Editor/KeyboardCustomizationSettings.cpp
index c4f9133f66..81d9375850 100644
--- a/Code/Editor/KeyboardCustomizationSettings.cpp
+++ b/Code/Editor/KeyboardCustomizationSettings.cpp
@@ -240,7 +240,7 @@ QJsonObject KeyboardCustomizationSettings::ExportGroup()
void KeyboardCustomizationSettings::ImportFromFile(QWidget* parent)
{
- QString fileName = QFileDialog::getOpenFileName(parent, QObject::tr("Export Keyboard Shortcuts"), QStringLiteral(""), QObject::tr("Keyboard Settings (*.keys)"));
+ QString fileName = QFileDialog::getOpenFileName(parent, QObject::tr("Export Keyboard Shortcuts"), QString(), QObject::tr("Keyboard Settings (*.keys)"));
if (fileName.isEmpty())
{
return;
diff --git a/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp b/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp
index 8c7023634e..63e59ea940 100644
--- a/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp
+++ b/Code/Editor/Lib/Tests/test_ViewportManipulatorController.cpp
@@ -85,6 +85,7 @@ namespace UnitTest
m_rootWidget = AZStd::make_unique();
m_rootWidget->setFixedSize(QSize(100, 100));
+ QApplication::setActiveWindow(m_rootWidget.get());
m_controllerList = AZStd::make_shared();
m_controllerList->RegisterViewportContext(TestViewportId);
@@ -100,6 +101,8 @@ namespace UnitTest
m_controllerList.reset();
m_rootWidget.reset();
+ QApplication::setActiveWindow(nullptr);
+
AllocatorsTestFixture::TearDown();
}
@@ -110,7 +113,7 @@ namespace UnitTest
const AzFramework::ViewportId ViewportManipulatorControllerFixture::TestViewportId = AzFramework::ViewportId(0);
- TEST_F(ViewportManipulatorControllerFixture, An_event_is_not_propagated_to_the_viewport_when_a_manipulator_handles_it_first)
+ TEST_F(ViewportManipulatorControllerFixture, AnEventIsNotPropagatedToTheViewportWhenAManipulatorHandlesItFirst)
{
// forward input events to our controller list
QObject::connect(
@@ -151,4 +154,77 @@ namespace UnitTest
editorInteractionViewportFake.Disconnect();
}
+
+ TEST_F(ViewportManipulatorControllerFixture, ChangingFocusDoesNotClearInput)
+ {
+ bool endedEvent = false;
+ // detect input events and ensure that the Alt key press does not end before the end of the test
+ QObject::connect(
+ m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(),
+ [&endedEvent](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event)
+ {
+ if (inputChannel->GetInputChannelId() == AzFramework::InputDeviceKeyboard::Key::ModifierAltL &&
+ inputChannel->IsStateEnded())
+ {
+ endedEvent = true;
+ }
+ });
+
+ // given
+ auto* secondaryWidget = new QWidget(m_rootWidget.get());
+
+ m_rootWidget->show();
+ secondaryWidget->show();
+
+ m_rootWidget->setFocus();
+
+ // simulate a key press when root widget has focus
+ QTest::keyPress(m_rootWidget.get(), Qt::Key_Alt, Qt::KeyboardModifier::AltModifier);
+
+ // when
+ // change focus to secondary widget
+ secondaryWidget->setFocus();
+
+ // then
+ // the alt key was not released (cleared)
+ EXPECT_FALSE(endedEvent);
+ }
+
+ // note: Application State Change includes events such as switching to another application or minimizing
+ // the current application
+ TEST_F(ViewportManipulatorControllerFixture, ApplicationStateChangeDoesClearInput)
+ {
+ bool endedEvent = false;
+ // detect input events and ensure that the Alt key press does not end before the end of the test
+ QObject::connect(
+ m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(),
+ [&endedEvent](const AzFramework::InputChannel* inputChannel, [[maybe_unused]] QEvent* event)
+ {
+ if (inputChannel->GetInputChannelId() == AzFramework::InputDeviceKeyboard::Key::AlphanumericW &&
+ inputChannel->IsStateEnded())
+ {
+ endedEvent = true;
+ }
+ });
+
+ // given
+ auto* secondaryWidget = new QWidget(m_rootWidget.get());
+
+ m_rootWidget->show();
+ secondaryWidget->show();
+
+ m_rootWidget->setFocus();
+
+ // simulate a key press when root widget has focus
+ QTest::keyPress(m_rootWidget.get(), Qt::Key_W);
+
+ // when
+ // simulate changing the window state
+ QApplicationStateChangeEvent applicationStateChangeEvent(Qt::ApplicationState::ApplicationInactive);
+ QCoreApplication::sendEvent(m_rootWidget.get(), &applicationStateChangeEvent);
+
+ // then
+ // the key was released (cleared)
+ EXPECT_TRUE(endedEvent);
+ }
} // namespace UnitTest
diff --git a/Code/Editor/MainStatusBar.cpp b/Code/Editor/MainStatusBar.cpp
index f955035bd8..acc7f664df 100644
--- a/Code/Editor/MainStatusBar.cpp
+++ b/Code/Editor/MainStatusBar.cpp
@@ -419,7 +419,7 @@ void MemoryStatusItem::updateStatus()
GeneralStatusItem::GeneralStatusItem(QString name, MainStatusBar* parent)
: StatusBarItem(name, parent)
{
- connect(parent, SIGNAL(messageChanged(QString)), this, SLOT(update()));
+ connect(parent, &MainStatusBar::messageChanged, this, [this](const QString&) { update(); });
}
QString GeneralStatusItem::CurrentText() const
diff --git a/Code/Editor/NewLevelDialog.cpp b/Code/Editor/NewLevelDialog.cpp
index 29445cef2b..c773acdb6f 100644
--- a/Code/Editor/NewLevelDialog.cpp
+++ b/Code/Editor/NewLevelDialog.cpp
@@ -100,9 +100,10 @@ CNewLevelDialog::CNewLevelDialog(QWidget* pParent /*=nullptr*/)
m_level = "";
// First of all, keyboard focus is related to widget tab order, and the default tab order is based on the order in which
// widgets are constructed. Therefore, creating more widgets changes the keyboard focus. That is why setFocus() is called last.
- // Secondly, using singleShot() allows setFocus() slot of the QLineEdit instance to be invoked right after the event system
- // is ready to do so. Therefore, it is better to use singleShot() than directly call setFocus().
- QTimer::singleShot(0, ui->LEVEL, SLOT(OnStartup()));
+ // in OnStartup()
+ // Secondly, using singleShot() allows OnStartup() slot of the QLineEdit instance to be invoked right after the event system
+ // is ready to do so. Therefore, it is better to use singleShot() than directly call OnStartup().
+ QTimer::singleShot(0, this, &CNewLevelDialog::OnStartup);
ReloadLevelFolder();
}
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
index 5b849dcbe7..82d9f9ede2 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
@@ -38,6 +38,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -642,6 +643,9 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con
AzToolsFramework::EntityIdList selected;
GetSelectedOrHighlightedEntities(selected);
+ bool prefabSystemEnabled = false;
+ AzFramework::ApplicationRequests::Bus::BroadcastResult(prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
+
QAction* action = nullptr;
// when nothing is selected, entity is created at root level
@@ -658,18 +662,20 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con
// when a single entity is selected, entity is created as its child
else if (selected.size() == 1)
{
- action = menu->addAction(QObject::tr("Create entity"));
- QObject::connect(
- action, &QAction::triggered, action,
- [selected]
- {
- EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, CreateNewEntityAsChild, selected.front());
- });
+ auto containerEntityInterface = AZ::Interface::Get();
+ if (!prefabSystemEnabled || (containerEntityInterface && containerEntityInterface->IsContainerOpen(selected.front())))
+ {
+ action = menu->addAction(QObject::tr("Create entity"));
+ QObject::connect(
+ action, &QAction::triggered, action,
+ [selected]
+ {
+ AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequestBus::Handler::CreateNewEntityAsChild, selected.front());
+ }
+ );
+ }
}
- bool prefabSystemEnabled = false;
- AzFramework::ApplicationRequests::Bus::BroadcastResult(prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
-
if (!prefabSystemEnabled)
{
menu->addSeparator();
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp
index d0091f968e..df8d6db4a8 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp
@@ -197,48 +197,46 @@ AssetCatalogModel::~AssetCatalogModel()
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
}
-AZ::Data::AssetType AssetCatalogModel::GetAssetType(QString filename) const
+AZ::Data::AssetType AssetCatalogModel::GetAssetType(const QString &filename) const
{
- AZ::Data::AssetType returnType = AZ::Uuid::CreateNull();
// Compare file extensions with the map created from the asset database.
int dotIndex = filename.lastIndexOf('.');
- if (dotIndex >= 0)
+ if (dotIndex < 0)
{
- QString extension = filename.mid(dotIndex);
- for (auto pair : m_extensionToAssetType)
- {
- QString qExtensions = pair.first.c_str();
- if (qExtensions.indexOf(extension) >= 0)
- {
- if (pair.second.size() > 1)
- {
- // There are multiple types with this extension. Check each handler to see if they can handle this data type.
- AZStd::string azFilename = filename.toStdString().c_str();
- EBUS_EVENT(AzFramework::ApplicationRequests::Bus, MakePathAssetRootRelative, azFilename);
- AZ::Data::AssetId assetId;
- EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, azFilename.c_str(), AZ::Data::s_invalidAssetType, false);
+ return AZ::Uuid::CreateNull();
+ }
- for (AZ::Uuid type : pair.second)
- {
- const AZ::Data::AssetHandler* handler = AZ::Data::AssetManager::Instance().GetHandler(type);
- if (handler && handler->CanHandleAsset(assetId))
- {
- returnType = type;
- break;
- }
- }
- }
- else
- {
- returnType = pair.second[0];
- break;
- }
+ QStringRef extension = filename.midRef(dotIndex);
+ for (const auto& pair : m_extensionToAssetType)
+ {
+ QString qExtensions = pair.first.c_str();
+ if (qExtensions.indexOf(extension) < 0 || pair.second.empty())
+ {
+ continue;
+ }
+ if (pair.second.size() == 1)
+ {
+ return pair.second[0];
+ }
+
+ // There are multiple types with this extension. Search for a handler that can handle this data type.
+ AZStd::string azFilename = filename.toStdString().c_str();
+ EBUS_EVENT(AzFramework::ApplicationRequests::Bus, MakePathAssetRootRelative, azFilename);
+ AZ::Data::AssetId assetId;
+ EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, azFilename.c_str(), AZ::Data::s_invalidAssetType, false);
+
+ for (const AZ::Uuid& type : pair.second)
+ {
+ const AZ::Data::AssetHandler* handler = AZ::Data::AssetManager::Instance().GetHandler(type);
+ if (handler && handler->CanHandleAsset(assetId))
+ {
+ return type;
}
}
}
- return returnType;
+ return AZ::Uuid::CreateNull();
}
QStandardItem* AssetCatalogModel::GetPath(QString& path, bool createIfNeeded, QStandardItem* parent)
@@ -419,7 +417,7 @@ AssetCatalogEntry* AssetCatalogModel::AddAsset(QString assetPath, AZ::Data::Asse
// icons' memory being reclaimed and crashing the Editor.
QSize size = fileIcon.actualSize(QSize(16, 16));
QIcon deepCopy = fileIcon.pixmap(size).copy(0, 0, size.width(), size.height());
-
+
if (!fileIcon.isNull())
{
m_assetTypeToIcon[assetType] = deepCopy;
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h
index c9143bb259..1dffa81d67 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h
@@ -110,7 +110,7 @@ protected:
void SetFilterRegExp(const AZStd::string& filterType, const QRegExp& regExp);
void ClearFilterRegExp(const AZStd::string& filterType = AZStd::string());
- AZ::Data::AssetType GetAssetType(QString filename) const;
+ AZ::Data::AssetType GetAssetType(const QString &filename) const;
QStandardItem* GetPath(QString& path, bool createIfNeeded, QStandardItem* parent = nullptr);
void ApplyFilter(QStandardItem* parent);
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
index dabf02e260..df8db79db0 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
@@ -215,11 +215,6 @@ namespace AZ
m_oldProjectPath = newProjectPath;
// Merge the project.json file into settings registry under ProjectSettingsRootKey path.
- AZ::IO::FixedMaxPath projectMetadataFile{ AZ::SettingsRegistryMergeUtils::FindEngineRoot(m_registry) / newProjectPath };
- projectMetadataFile /= "project.json";
- m_registry.MergeSettingsFile(projectMetadataFile.Native(),
- AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey);
-
// Update all the runtime file paths based on the new "project_path" value.
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry);
}
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp
index 533d55ed27..8e15871bc0 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp
@@ -56,15 +56,21 @@ namespace AZ::ComponentApplicationLifecycle
}
bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
- AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName)
+ AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent)
{
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
using Type = AZ::SettingsRegistryInterface::Type;
using NotifyEventHandler = AZ::SettingsRegistryInterface::NotifyEventHandler;
- if (!ValidateEvent(settingsRegistry, eventName))
+ // Some systems may attempt to register a handler before the settings registry has been loaded
+ // If so, this flag lets them automatically register an event if it hasn't yet been registered.
+ // RegisterEvent calls validate event.
+ if ((!autoRegisterEvent && !ValidateEvent(settingsRegistry, eventName)) ||
+ (autoRegisterEvent && !RegisterEvent(settingsRegistry, eventName)))
{
- AZ_Warning("ComponentApplicationLifecycle", false, R"(Cannot register event %.*s. Name does is not a field of object "%.*s".)"
+ AZ_Warning(
+ "ComponentApplicationLifecycle", false,
+ R"(Cannot register event %.*s. Name is not a field of object "%.*s".)"
R"( Please make sure the entry exists in the '/Registry/application_lifecycle_events.setreg")"
" or in *.setreg within the project", AZ_STRING_ARG(eventName), AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey));
return false;
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h
index 5fc6c4b2c3..6f07c0da3f 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h
@@ -14,7 +14,7 @@
namespace AZ::ComponentApplicationLifecycle
{
//! Root Key where lifecycle events should be registered under
- inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Runtime/Application/LifecycleEvents";
+ inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Application/LifecycleEvents";
//! Validates that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey
@@ -48,7 +48,9 @@ namespace AZ::ComponentApplicationLifecycle
//! if the specified @eventName passes validation
//! @param callback will be moved into the handler if the specified @eventName is valid
//! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to register
+ //! @param autoRegisterEvent automatically register this event if it hasn't been registered yet. This is useful
+ //! when registering a handler before the settings registry has been loaded.
//! @return true if the handler was registered with the SettingsRegistry NotifyEvent
bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler,
- AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName);
+ AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName, bool autoRegisterEvent = false);
}
diff --git a/Code/Framework/AzCore/AzCore/Component/TransformBus.h b/Code/Framework/AzCore/AzCore/Component/TransformBus.h
index 1af77da51b..f8e30147da 100644
--- a/Code/Framework/AzCore/AzCore/Component/TransformBus.h
+++ b/Code/Framework/AzCore/AzCore/Component/TransformBus.h
@@ -168,6 +168,11 @@ namespace AZ
//! Rotation modifiers
//! @{
+ //! Set the world rotation matrix using the composition of rotations around
+ //! the principle axes in the order of z-axis first and y-axis and then x-axis.
+ //! @param eulerRadianAngles A Vector3 denoting radian angles of the rotations around each principle axis.
+ virtual void SetWorldRotation([[maybe_unused]] const AZ::Vector3& eulerAnglesRadian) {}
+
//! Sets the entity's rotation in the world in quaternion notation.
//! The origin of the axes is the entity's position in world space.
//! @param quaternion A quaternion that represents the rotation to use for the entity.
diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp
index 0bb92b923d..0cb77b2d6e 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp
+++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp
@@ -7,4 +7,63 @@
*/
#include
+#include
+#include
+#include
+#include
+namespace AZ::Debug
+{
+ AZStd::string GenerateOutputFile(const char* nameHint)
+ {
+ AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation();
+ return AZStd::string::format("%s/capture_%s_%lld.json", captureOutput.c_str(), nameHint, AZStd::GetTimeNowSecond());
+ }
+
+ void ProfilerCaptureFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
+ {
+ if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem)
+ {
+ AZStd::string captureFile = GenerateOutputFile("single");
+ AZLOG_INFO("Setting capture file to %s", captureFile.c_str());
+ profilerSystem->CaptureFrame(captureFile);
+ }
+ }
+ AZ_CONSOLEFREEFUNC(ProfilerCaptureFrame, AZ::ConsoleFunctorFlags::DontReplicate, "Capture a single frame of profiling data");
+
+ void ProfilerStartCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
+ {
+ if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem)
+ {
+ AZStd::string captureFile = GenerateOutputFile("multi");
+ AZLOG_INFO("Setting capture file to %s", captureFile.c_str());
+ profilerSystem->StartCapture(AZStd::move(captureFile));
+ }
+ }
+ AZ_CONSOLEFREEFUNC(ProfilerStartCapture, AZ::ConsoleFunctorFlags::DontReplicate, "Start a multi-frame capture of profiling data");
+
+ void ProfilerEndCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
+ {
+ if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem)
+ {
+ profilerSystem->EndCapture();
+ }
+ }
+ AZ_CONSOLEFREEFUNC(ProfilerEndCapture, AZ::ConsoleFunctorFlags::DontReplicate, "End and dump an in-progress continuous capture");
+
+ AZ::IO::FixedMaxPathString GetProfilerCaptureLocation()
+ {
+ AZ::IO::FixedMaxPathString captureOutput;
+ if (AZ::SettingsRegistryInterface* settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry)
+ {
+ settingsRegistry->Get(captureOutput, RegistryKey_ProfilerCaptureLocation);
+ }
+
+ if (captureOutput.empty())
+ {
+ captureOutput = ProfilerCaptureLocationFallback;
+ }
+
+ return captureOutput;
+ }
+} // namespace AZ::Debug
diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h
index 1537be3b81..322bfb60c2 100644
--- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h
+++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h
@@ -9,11 +9,20 @@
#pragma once
#include
+#include
+#include
+#include
namespace AZ
{
namespace Debug
{
+ //! settings registry entry for specifying where to output profiler captures
+ static constexpr const char* RegistryKey_ProfilerCaptureLocation = "/O3DE/AzCore/Debug/Profiler/CaptureLocation";
+
+ //! fallback value in the event the settings registry isn't ready or doesn't contain the key
+ static constexpr const char* ProfilerCaptureLocationFallback = "@user@/Profiler";
+
/**
* ProfilerNotifications provides a profiler event interface that can be used to update listeners on profiler status
*/
@@ -23,32 +32,38 @@ namespace AZ
public:
virtual ~ProfilerNotifications() = default;
- virtual void OnProfileSystemInitialized() = 0;
+ //! Notify when the current profiler capture is finished
+ //! @param result Set to true if it's finished successfully
+ //! @param info The output file path or error information which depends on the return.
+ virtual void OnCaptureFinished(bool result, const AZStd::string& info) = 0;
};
using ProfilerNotificationBus = AZ::EBus;
- enum class ProfileFrameAdvanceType
- {
- Game,
- Render,
- Default = Game
- };
-
/**
* ProfilerRequests provides an interface for making profiling system requests
*/
class ProfilerRequests
- : public AZ::EBusTraits
{
public:
- // Allow multiple threads to concurrently make requests
- using MutexType = AZStd::mutex;
-
+ AZ_RTTI(ProfilerRequests, "{90AEC117-14C1-4BAE-9704-F916E49EF13F}");
virtual ~ProfilerRequests() = default;
- virtual bool IsActive() = 0;
- virtual void FrameAdvance(ProfileFrameAdvanceType type) = 0;
+ //! Getter/setter for the profiler active state
+ virtual bool IsActive() const = 0;
+ virtual void SetActive(bool active) = 0;
+
+ //! Capture a single frame of profiling data
+ virtual bool CaptureFrame(const AZStd::string& outputFilePath) = 0;
+
+ //! Starting/ending a multi-frame capture of profiling data
+ virtual bool StartCapture(AZStd::string outputFilePath) = 0;
+ virtual bool EndCapture() = 0;
};
- using ProfilerRequestBus = AZ::EBus;
- }
-}
+
+ using ProfilerSystemInterface = AZ::Interface;
+
+ //! helper function for getting the profiler capture location from the settings registry that
+ //! includes fallback handing in the event the registry value can't be determined
+ AZ::IO::FixedMaxPathString GetProfilerCaptureLocation();
+ } // namespace Debug
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp
new file mode 100644
index 0000000000..42151a6996
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+namespace AZ::Debug
+{
+ static constexpr const char* ProfilerScriptCategory = "Profiler";
+ static constexpr const char* ProfilerScriptModule = "debug";
+ static constexpr AZ::Script::Attributes::ScopeFlags ProfilerScriptScope = AZ::Script::Attributes::ScopeFlags::Automation;
+
+ class ProfilerNotificationBusHandler final
+ : public ProfilerNotificationBus::Handler
+ , public AZ::BehaviorEBusHandler
+ {
+ public:
+ AZ_EBUS_BEHAVIOR_BINDER(ProfilerNotificationBusHandler, "{44161459-B816-4876-95A4-BA16DEC767D6}", AZ::SystemAllocator,
+ OnCaptureFinished
+ );
+
+ void OnCaptureFinished(bool result, const AZStd::string& info) override
+ {
+ Call(FN_OnCaptureFinished, result, info);
+ }
+
+ static void Reflect(AZ::ReflectContext* context)
+ {
+ if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context))
+ {
+ behaviorContext->EBus("ProfilerNotificationBus")
+ ->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory)
+ ->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule)
+ ->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope)
+ ->Handler();
+ }
+ }
+ };
+
+ class ProfilerSystemScriptProxy
+ : public BehaviorInterfaceProxy
+ {
+ public:
+ AZ_RTTI(ProfilerSystemScriptProxy, "{D671FB70-8B09-4C3A-96CD-06A339F3138E}", BehaviorInterfaceProxy);
+
+ AZ_BEHAVIOR_INTERFACE(ProfilerSystemScriptProxy, ProfilerRequests);
+ };
+
+ void ProfilerReflect(AZ::ReflectContext* context)
+ {
+ if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context))
+ {
+ behaviorContext->ConstantProperty("g_ProfilerSystem", ProfilerSystemScriptProxy::GetProxy)
+ ->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory)
+ ->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule)
+ ->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope);
+
+ behaviorContext->Class("ProfilerSystemInterface")
+ ->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory)
+ ->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule)
+ ->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope)
+
+ ->Method("IsValid", &ProfilerSystemScriptProxy::IsValid)
+
+ ->Method("GetCaptureLocation",
+ [](ProfilerSystemScriptProxy*) -> AZStd::string
+ {
+ AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation();
+ return AZStd::string(captureOutput.c_str(), captureOutput.length());
+ })
+
+ ->Method("IsActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::IsActive>())
+ ->Method("SetActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::SetActive>())
+
+ ->Method("CaptureFrame", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::CaptureFrame>())
+
+ ->Method("StartCapture", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::StartCapture>())
+ ->Method("EndCapture", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::EndCapture>());
+ }
+
+ ProfilerNotificationBusHandler::Reflect(context);
+ }
+} // namespace AZ::Debug
diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.h
new file mode 100644
index 0000000000..d6857defe5
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+#pragma once
+
+namespace AZ
+{
+ class ReflectContext;
+
+ namespace Debug
+ {
+ //! Reflects the profiler bus script bindings
+ void ProfilerReflect(AZ::ReflectContext* context);
+ } // namespace Debug
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp
index 357149d096..b9e4003500 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp
+++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp
@@ -27,26 +27,21 @@
#include
#include
-namespace AZ
+namespace AZ::Debug
{
- namespace Debug
+ struct StackFrame;
+
+ namespace Platform
{
- struct StackFrame;
-
- namespace Platform
- {
#if defined(AZ_ENABLE_DEBUG_TOOLS)
- bool AttachDebugger();
- bool IsDebuggerPresent();
- void HandleExceptions(bool isEnabled);
- void DebugBreak();
+ bool AttachDebugger();
+ bool IsDebuggerPresent();
+ void HandleExceptions(bool isEnabled);
+ void DebugBreak();
#endif
- void Terminate(int exitCode);
- }
+ void Terminate(int exitCode);
}
- using namespace AZ::Debug;
-
namespace DebugInternal
{
// other threads can trigger fatals and errors, but the same thread should not, to avoid stack overflow.
@@ -60,7 +55,7 @@ namespace AZ
// Globals
const int g_maxMessageLength = 4096;
static const char* g_dbgSystemWnd = "System";
- Trace Debug::g_tracer;
+ Trace g_tracer;
void* g_exceptionInfo = nullptr;
// Environment var needed to track ignored asserts across systems and disable native UI under certain conditions
@@ -616,4 +611,4 @@ namespace AZ
val.Set(level);
}
}
-} // namspace AZ
+} // namspace AZ::Debug
diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp
index 9728866fb6..9a465021c2 100644
--- a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp
@@ -156,7 +156,10 @@ namespace AZ
void StreamerComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
bool isEnabled = false;
- AZ::Debug::ProfilerRequestBus::BroadcastResult(isEnabled, &AZ::Debug::ProfilerRequests::IsActive);
+ if (auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); profilerSystem)
+ {
+ isEnabled = profilerSystem->IsActive();
+ }
if (isEnabled)
{
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl
index e228a19d68..8355f9bfe0 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl
@@ -383,36 +383,36 @@ namespace AZ
AZ_MATH_INLINE bool CmpAllEq(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpNeq(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpEq(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllLt(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpGtEq(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpLt(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllLtEq(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpGt(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpLtEq(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllGt(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpLtEq(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpGt(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllGtEq(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpLt(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpGtEq(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl
index ecdcf40743..bb332c03a2 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl
@@ -331,31 +331,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec1::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x000F);
+ // Only check the first bit for Vector1
+ return Sse::CmpAllEq(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0x000F);
+ return Sse::CmpAllLt(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0x000F);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0x000F);
+ return Sse::CmpAllGt(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0x000F);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b0001);
}
@@ -397,7 +398,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec1::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x000F);
+ return Sse::CmpAllEq(arg1, arg2, 0b0001);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl
index c890aa5eb7..90fb97e694 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl
@@ -383,31 +383,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec2::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x00FF);
+ // Only check the first two bits for Vector2
+ return Sse::CmpAllEq(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0x00FF);
+ return Sse::CmpAllLt(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0x00FF);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0x00FF);
+ return Sse::CmpAllGt(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0x00FF);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b0011);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl
index a8ff962837..31e8d19d65 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl
@@ -419,31 +419,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec3::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x0FFF);
+ // Only check the first three bits for Vector3
+ return Sse::CmpAllEq(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllLt(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllGt(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b0111);
}
@@ -485,7 +486,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec3::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllEq(arg1, arg2, 0b0111);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl
index 1cf0a35d7f..f3a4feb524 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl
@@ -455,31 +455,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec4::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0xFFFF);
+ // Check the first four bits for Vector4
+ return Sse::CmpAllEq(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllLt(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllGt(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b1111);
}
@@ -521,7 +522,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec4::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllEq(arg1, arg2, 0b1111);
}
diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h
new file mode 100644
index 0000000000..0e7a4ac356
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+namespace AZ
+{
+ /**
+ * Utility class for reflecting an AZ::Interface through the BehaviorContext
+ *
+ * Example:
+ *
+ * class MyInterface
+ * {
+ * public:
+ * AZ_RTTI(MyInterface, "{BADDF000D-CDCD-CDCD-CDCD-BAAAADF0000D}");
+ * virtual ~MyInterface() = default;
+ *
+ * virtual AZStd::string Foo() = 0;
+ * virtual void Bar(float x, float y) = 0;
+ * };
+ *
+ * class MySystemProxy
+ * : public BehaviorInterfaceProxy
+ * {
+ * public:
+ * AZ_RTTI(MySystemProxy, "{CDCDCDCD-BAAD-BADD-F00D-CDCDCDCDCDCD}", BehaviorInterfaceProxy);
+ * AZ_BEHAVIOR_INTERFACE(MySystemProxy, MyInterface);
+ * };
+ *
+ * void Reflect(AZ::ReflectContext* context)
+ * {
+ * if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context))
+ * {
+ * behaviorContext->ConstantProperty("g_MySystem", MySystemProxy::GetProxy)
+ * ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ * ->Attribute(AZ::Script::Attributes::Module, "MyModule");
+ *
+ * behaviorContext->Class("MySystemInterface")
+ * ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ * ->Attribute(AZ::Script::Attributes::Module, "MyModule")
+ *
+ * ->Method("Foo", MySystemProxy::WrapMethod<&MyInterface::Foo>())
+ * ->Method("Bar", MySystemProxy::WrapMethod<&MyInterface::Bar>());
+ * }
+ * }
+ */
+ template
+ class BehaviorInterfaceProxy
+ {
+ public:
+ AZ_CLASS_ALLOCATOR(BehaviorInterfaceProxy, AZ::SystemAllocator, 0);
+ AZ_RTTI(BehaviorInterfaceProxy, "{E7CC8D27-4499-454E-A7DF-3F72FBECD30D}");
+
+ BehaviorInterfaceProxy() = default;
+ virtual ~BehaviorInterfaceProxy() = default;
+
+ //! Stores the instance which will use the provided shared_ptr deleter when the reference count hits zero
+ BehaviorInterfaceProxy(AZStd::shared_ptr sharedInstance)
+ : m_instance(AZStd::move(sharedInstance))
+ {
+ }
+
+ //! Stores the instance which will perform a no-op deleter when the reference count hits zero
+ BehaviorInterfaceProxy(T* rawIntance)
+ : m_instance(rawIntance, [](T*) {})
+ {
+ }
+
+ //! Returns if the m_instance shared pointer is non-nullptr
+ bool IsValid() const { return m_instance; }
+
+ protected:
+ //! Internal access for use in the derived GetProxy function
+ static T* GetInstance()
+ {
+ T* interfacePtr = AZ::Interface::Get();
+ AZ_Warning("BehaviorInterfaceProxy", interfacePtr,
+ "There is currently no global %s registered with an AZ Interface",
+ AzTypeInfo::Name()
+ );
+ // Don't delete the global instance, it is not owned by the behavior context
+ return interfacePtr;
+ }
+
+ template
+ struct MethodWrapper
+ {
+ template
+ static auto WrapMethod()
+ {
+ using ReturnType = AZStd::function_traits_get_result_t>;
+ return [](Proxy* proxy, Args... params) -> ReturnType
+ {
+ if (proxy && proxy->IsValid())
+ {
+ return AZStd::invoke(Method, proxy->m_instance, AZStd::forward(params)...);
+ }
+ return ReturnType();
+ };
+ }
+ };
+
+ AZStd::shared_ptr m_instance;
+ };
+
+ #define AZ_BEHAVIOR_INTERFACE(ProxyType, InterfaceType) \
+ static ProxyType GetProxy() { return GetInstance(); } \
+ template \
+ static auto WrapMethod() { \
+ using FuncTraits = AZStd::function_traits>; \
+ return FuncTraits::template expand_args::template WrapMethod(); \
+ } \
+ ProxyType() = default; \
+ ProxyType(AZStd::shared_ptr sharedInstance) : BehaviorInterfaceProxy(sharedInstance) {} \
+ ProxyType(InterfaceType* rawIntance) : BehaviorInterfaceProxy(rawIntance) {}
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp
index a83232c8cb..3b2aebdee6 100644
--- a/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -87,6 +88,8 @@ void ScriptSystemComponent::Activate()
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, "lua");
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, "luac");
+ AZ::Data::AssetCatalogRequestBus::Broadcast(
+ &AZ::Data::AssetCatalogRequests::EnableCatalogForAsset, AZ::AzTypeInfo::Uuid());
if (Data::AssetManager::Instance().IsReady())
{
@@ -925,6 +928,7 @@ void ScriptSystemComponent::Reflect(ReflectContext* reflection)
// reflect default entity
MathReflect(behaviorContext);
ScriptDebug::Reflect(behaviorContext);
+ Debug::ProfilerReflect(behaviorContext);
Debug::TraceReflect(behaviorContext);
behaviorContext->Class("Platform")
diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
index 36f66312d8..5458a3fadf 100644
--- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
+++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp
@@ -634,12 +634,18 @@ namespace AZ::SettingsRegistryMergeUtils
}
// Project name - if it was set via merging project.json use that value, otherwise use the project path's folder name.
- auto projectNameKey =
- AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
+ constexpr auto projectNameKey =
+ FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey)
+ "/project_name";
- AZ::SettingsRegistryInterface::FixedValueString projectName;
- if (!registry.Get(projectName, projectNameKey))
+ // Read the project name from the project.json file if it exists
+ if (AZ::IO::FixedMaxPath projectJsonPath = normalizedProjectPath / "project.json";
+ AZ::IO::SystemFile::Exists(projectJsonPath.c_str()))
+ {
+ registry.MergeSettingsFile(projectJsonPath.Native(),
+ AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey);
+ }
+ if (FixedValueString projectName; !registry.Get(projectName, projectNameKey))
{
projectName = path.Filename().Native();
registry.Set(projectNameKey, projectName);
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
index 4097348798..08cfb11d34 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
@@ -363,7 +363,11 @@ namespace AZ
{
++m_graphsRemaining;
- event->m_executor = this; // Used to validate event is not waited for inside a job
+ if (event)
+ {
+ event->IncWaitCount();
+ event->m_executor = this; // Used to validate event is not waited for inside a job
+ }
// Submit all tasks that have no inbound edges
for (Internal::Task& task : graph.Tasks())
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
index f57b06890a..eeb46d6887 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
@@ -20,6 +20,46 @@ namespace AZ
m_semaphore.acquire();
}
+ void TaskGraphEvent::IncWaitCount()
+ {
+ // guess zero to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
+ int expectedValue = 0;
+ while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue + 1))
+ {
+ // value will be negative once event is ready to signal or has been signaled. Shouldn't happen.
+ AZ_Assert(expectedValue >= 0, "Called TaskGraphEvent::IncWaitCount on a signalled event");
+ if (expectedValue < 0) // event already signaled, skip
+ {
+ return;
+ }
+ };
+ }
+
+ void TaskGraphEvent::Signal()
+ {
+ // guess one to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
+ int expectedValue = 1;
+ while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue - 1))
+ {
+ // It's an error for Signal to be called if no one is waiting, or the event has already been signaled
+ AZ_Assert(expectedValue > 0, "Called TaskGraphEvent::Signal when event is either signaled or unused");
+ if (expectedValue < 0) // return if already signaled
+ {
+ return;
+ }
+ };
+
+ if (expectedValue == 1) // This call to Signal decremented the value to 0.
+ {
+ expectedValue = 0;
+ // validate no one incremented the wait count and mark signalling state
+ if (m_waitCount.compare_exchange_strong(expectedValue, -1))
+ {
+ m_semaphore.release();
+ }
+ }
+ }
+
void TaskToken::PrecedesInternal(TaskToken& comesAfter)
{
AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted.");
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
index 9553013a4b..fa6f5dbe94 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
@@ -61,14 +61,14 @@ namespace AZ
uint32_t m_index;
};
- // A TaskGraphEvent may be used to block until a task graph has finished executing. Usage
+ // A TaskGraphEvent may be used to block until one or more task graphs has finished executing. Usage
// is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting
// the graph without synchronization over the course of the frame). However, the event
// is useful for the edges of the computation graph.
//
// You are responsible for ensuring the event object lifetime exceeds the task graph lifetime.
//
- // After the TaskGraphEvent is signaled, you are allowed to reuse the same TaskGraphEvent
+ // After the TaskGraphEvent is signaled, you are NOT allowed to reuse the same TaskGraphEvent
// for a future submission.
class TaskGraphEvent
{
@@ -81,10 +81,12 @@ namespace AZ
friend class TaskGraph;
friend class TaskExecutor;
+ void IncWaitCount();
void Signal();
AZStd::binary_semaphore m_semaphore;
- TaskExecutor* m_executor = nullptr;
+ AZStd::atomic_int m_waitCount = 0;
+ TaskExecutor* m_executor = nullptr;
};
// The TaskGraph encapsulates a set of tasks and their interdependencies. After adding
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
index 7b2f0cefdc..9a5289eb82 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
@@ -33,11 +33,6 @@ namespace AZ
return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 });
}
- inline void TaskGraphEvent::Signal()
- {
- m_semaphore.release();
- }
-
template
TaskToken TaskGraph::AddTask(TaskDescriptor const& desc, Lambda&& lambda)
{
diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake
index 6a9e5a29d6..a5cc3fdcd4 100644
--- a/Code/Framework/AzCore/AzCore/azcore_files.cmake
+++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake
@@ -108,6 +108,8 @@ set(FILES
Debug/Profiler.inl
Debug/Profiler.h
Debug/ProfilerBus.h
+ Debug/ProfilerReflection.cpp
+ Debug/ProfilerReflection.h
Debug/StackTracer.h
Debug/EventTrace.h
Debug/EventTrace.cpp
@@ -456,6 +458,7 @@ set(FILES
RTTI/BehaviorContext.h
RTTI/BehaviorContextUtilities.h
RTTI/BehaviorContextUtilities.cpp
+ RTTI/BehaviorInterfaceProxy.h
RTTI/BehaviorObjectSignals.h
RTTI/TypeSafeIntegral.h
Script/ScriptAsset.cpp
diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
index 28d3459ba3..4535387902 100644
--- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
+++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
@@ -17,7 +17,7 @@
#include
-namespace AZ
+namespace AZ::Debug
{
#if defined(AZ_ENABLE_DEBUG_TOOLS)
LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo);
@@ -26,94 +26,91 @@ namespace AZ
constexpr int g_maxMessageLength = 4096;
- namespace Debug
+ namespace Platform
{
- namespace Platform
- {
#if defined(AZ_ENABLE_DEBUG_TOOLS)
- bool IsDebuggerPresent()
+ bool IsDebuggerPresent()
+ {
+ return ::IsDebuggerPresent() ? true : false;
+ }
+
+ void HandleExceptions(bool isEnabled)
+ {
+ if (isEnabled)
{
- return ::IsDebuggerPresent() ? true : false;
+ g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler);
}
-
- void HandleExceptions(bool isEnabled)
+ else
{
- if (isEnabled)
- {
- g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler);
- }
- else
- {
- ::SetUnhandledExceptionFilter(g_previousExceptionHandler);
- g_previousExceptionHandler = NULL;
- }
- }
-
- bool AttachDebugger()
- {
- if (IsDebuggerPresent())
- {
- return true;
- }
-
- // Launch vsjitdebugger.exe, this app is always present in System32 folder
- // with an installation of any version of visual studio.
- // It will open a debugging dialog asking the user what debugger to use
-
- STARTUPINFOW startupInfo = {0};
- startupInfo.cb = sizeof(startupInfo);
- PROCESS_INFORMATION processInfo = {0};
-
- wchar_t cmdline[MAX_PATH];
- swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
- bool success = ::CreateProcessW(
- NULL, // No module name (use command line)
- cmdline, // Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- FALSE, // No handle inheritance
- 0, // No creation flags
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &startupInfo, // Pointer to STARTUPINFO structure
- &processInfo); // Pointer to PROCESS_INFORMATION structure
-
- if (success)
- {
- ::WaitForSingleObject(processInfo.hProcess, INFINITE);
- ::CloseHandle(processInfo.hProcess);
- ::CloseHandle(processInfo.hThread);
- return true;
- }
- return false;
- }
-
- void DebugBreak()
- {
- __debugbreak();
- }
-#endif // AZ_ENABLE_DEBUG_TOOLS
-
- void Terminate(int exitCode)
- {
- TerminateProcess(GetCurrentProcess(), exitCode);
- }
-
- void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
- {
- AZStd::fixed_wstring tmpW;
- if(window)
- {
- AZStd::to_wstring(tmpW, window);
- tmpW += L": ";
- OutputDebugStringW(tmpW.c_str());
- tmpW.clear();
- }
- AZStd::to_wstring(tmpW, message);
- OutputDebugStringW(tmpW.c_str());
+ ::SetUnhandledExceptionFilter(g_previousExceptionHandler);
+ g_previousExceptionHandler = NULL;
}
}
- }
+
+ bool AttachDebugger()
+ {
+ if (IsDebuggerPresent())
+ {
+ return true;
+ }
+
+ // Launch vsjitdebugger.exe, this app is always present in System32 folder
+ // with an installation of any version of visual studio.
+ // It will open a debugging dialog asking the user what debugger to use
+
+ STARTUPINFOW startupInfo = {0};
+ startupInfo.cb = sizeof(startupInfo);
+ PROCESS_INFORMATION processInfo = {0};
+
+ wchar_t cmdline[MAX_PATH];
+ swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
+ bool success = ::CreateProcessW(
+ NULL, // No module name (use command line)
+ cmdline, // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ FALSE, // No handle inheritance
+ 0, // No creation flags
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &startupInfo, // Pointer to STARTUPINFO structure
+ &processInfo); // Pointer to PROCESS_INFORMATION structure
+
+ if (success)
+ {
+ ::WaitForSingleObject(processInfo.hProcess, INFINITE);
+ ::CloseHandle(processInfo.hProcess);
+ ::CloseHandle(processInfo.hThread);
+ return true;
+ }
+ return false;
+ }
+
+ void DebugBreak()
+ {
+ __debugbreak();
+ }
+#endif // AZ_ENABLE_DEBUG_TOOLS
+
+ void Terminate(int exitCode)
+ {
+ TerminateProcess(GetCurrentProcess(), exitCode);
+ }
+
+ void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
+ {
+ AZStd::fixed_wstring tmpW;
+ if(window)
+ {
+ AZStd::to_wstring(tmpW, window);
+ tmpW += L": ";
+ OutputDebugStringW(tmpW.c_str());
+ tmpW.clear();
+ }
+ AZStd::to_wstring(tmpW, message);
+ OutputDebugStringW(tmpW.c_str());
+ }
+ } // namespace Platform
#if defined(AZ_ENABLE_DEBUG_TOOLS)
@@ -187,6 +184,8 @@ namespace AZ
azsnprintf(message, g_maxMessageLength, "Exception : 0x%lX - '%s' [%p]\n", ExceptionInfo->ExceptionRecord->ExceptionCode, GetExeptionName(ExceptionInfo->ExceptionRecord->ExceptionCode), ExceptionInfo->ExceptionRecord->ExceptionAddress);
Debug::Trace::Instance().Output(nullptr, message);
+ Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
+
EBUS_EVENT(Debug::TraceMessageDrillerBus, OnException, message);
bool result = false;
@@ -198,7 +197,7 @@ namespace AZ
// if someone ever returns TRUE we assume that they somehow handled this exception and continue.
return EXCEPTION_CONTINUE_EXECUTION;
}
- Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
+
Debug::Trace::Instance().Output(nullptr, "==================================================================\n");
// allowing continue of execution is not valid here. This handler gets called for serious exceptions.
@@ -211,4 +210,4 @@ namespace AZ
}
#endif
-}
+} // namspace AZ::Debug
diff --git a/Code/Framework/AzCore/Tests/TaskTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp
index 9e839f60ee..4f53772d51 100644
--- a/Code/Framework/AzCore/Tests/TaskTests.cpp
+++ b/Code/Framework/AzCore/Tests/TaskTests.cpp
@@ -610,15 +610,16 @@ namespace UnitTest
g.Follows(e, f);
g.Precedes(d);
- TaskGraphEvent ev;
- graph.SubmitOnExecutor(*m_executor, &ev);
- ev.Wait();
+ TaskGraphEvent ev1;
+ graph.SubmitOnExecutor(*m_executor, &ev1);
+ ev1.Wait();
EXPECT_EQ(3 | 0b100000, x);
x = 0;
- graph.SubmitOnExecutor(*m_executor, &ev);
- ev.Wait();
+ TaskGraphEvent ev2;
+ graph.SubmitOnExecutor(*m_executor, &ev2);
+ ev2.Wait();
EXPECT_EQ(3 | 0b100000, x);
}
diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
index 8fb986802e..323e834413 100644
--- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
@@ -204,7 +204,6 @@ namespace AzFramework
systemEntity->Activate();
AZ_Assert(systemEntity->GetState() == AZ::Entity::State::Active, "System Entity failed to activate.");
-
if (m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); m_isStarted)
{
if (m_startupParameters.m_loadAssetCatalog)
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
index cd30b753b5..c1c5775958 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
@@ -12,6 +12,7 @@
#include
#include
+#include
#include
#include
#include
@@ -363,6 +364,23 @@ namespace AZ::IO
, m_mainThreadId{ AZStd::this_thread::get_id() }
{
CompressionBus::Handler::BusConnect();
+
+ // If the settings registry is not available at this point,
+ // then something catastrophic has happened in the application startup.
+ // That should have been caught and messaged out earlier in startup.
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ // Automatically register the event if it's not registered, because
+ // this system is initialized before the settings registry has loaded the event list.
+ AZ::ComponentApplicationLifecycle::RegisterHandler(
+ *settingsRegistry, m_componentApplicationLifecycleHandler,
+ [this](AZStd::string_view /*path*/, AZ::SettingsRegistryInterface::Type /*type*/)
+ {
+ OnSystemEntityActivated();
+ },
+ "SystemComponentsActivated",
+ /*autoRegisterEvent*/ true);
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -1175,13 +1193,20 @@ namespace AZ::IO
}
}
- auto bundleManifest = GetBundleManifest(desc.pZip);
AZStd::shared_ptr bundleCatalog;
+ auto bundleManifest = GetBundleManifest(desc.pZip);
if (bundleManifest)
{
bundleCatalog = GetBundleCatalog(desc.pZip, bundleManifest->GetCatalogName());
}
+ // If this archive is loaded before the serialize context is available, then the manifest and catalog will need to be loaded later.
+ if (!bundleManifest || !bundleCatalog)
+ {
+ m_archivesWithCatalogsToLoad.push_back(
+ ArchivesWithCatalogsToLoad(szFullPath, szBindRoot, flags, nextBundle, desc.m_strFileName));
+ }
+
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
@@ -1219,12 +1244,17 @@ namespace AZ::IO
m_levelOpenEvent.Signal(levelDirs);
}
- AZ::IO::ArchiveNotificationBus::Broadcast([](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
- AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle, AZStd::shared_ptr bundleCatalog)
+ if (bundleManifest && bundleCatalog)
{
- archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
- }, desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
-
+ AZ::IO::ArchiveNotificationBus::Broadcast(
+ [](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
+ AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
+ AZStd::shared_ptr bundleCatalog)
+ {
+ archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
+ },
+ desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
+ }
return true;
}
@@ -2138,7 +2168,7 @@ namespace AZ::IO
}
currentDirPattern = currentDir + AZ_FILESYSTEM_SEPARATOR_WILDCARD;
- currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "levels.pak";
+ currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "level.pak";
ZipDir::FileEntry* fileEntry = findFile.FindExact(currentFilePattern.c_str());
if (fileEntry)
@@ -2175,4 +2205,36 @@ namespace AZ::IO
return catalogInfo;
}
+
+ void Archive::OnSystemEntityActivated()
+ {
+ for (const auto& archiveInfo : m_archivesWithCatalogsToLoad)
+ {
+ AZStd::intrusive_ptr archive =
+ OpenArchive(archiveInfo.m_fullPath, archiveInfo.m_bindRoot, archiveInfo.m_flags, nullptr);
+ if (!archive)
+ {
+ continue;
+ }
+
+ ZipDir::CachePtr pZip = static_cast(archive.get())->GetCache();
+
+ AZStd::shared_ptr bundleCatalog;
+ auto bundleManifest = GetBundleManifest(pZip);
+ if (bundleManifest)
+ {
+ bundleCatalog = GetBundleCatalog(pZip, bundleManifest->GetCatalogName());
+ }
+
+ AZ::IO::ArchiveNotificationBus::Broadcast(
+ [](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
+ AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
+ AZStd::shared_ptr bundleCatalog)
+ {
+ archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
+ },
+ archiveInfo.m_strFileName.c_str(), bundleManifest, archiveInfo.m_nextBundle, bundleCatalog);
+ }
+ m_archivesWithCatalogsToLoad.clear();
+ }
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
index f08d90a66e..279702b433 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -271,6 +272,11 @@ namespace AZ::IO
ZipDir::CachePtr* pZip = {}) const;
private:
+ // Archives can't be fully mounted until the system entity has been activated,
+ // because mounting them requires the BundlingSystemComponent and the serialization system
+ // to both be available.
+ void OnSystemEntityActivated();
+
bool OpenPackCommon(AZStd::string_view szBindRoot, AZStd::string_view pName, AZStd::intrusive_ptr pData = nullptr, bool addLevels = true);
bool OpenPacksCommon(AZStd::string_view szDir, AZStd::string_view pWildcardIn, AZStd::vector* pFullPaths = nullptr, bool addLevels = true);
@@ -313,6 +319,8 @@ namespace AZ::IO
mutable AZStd::shared_mutex m_csZips;
ZipArray m_arrZips;
+ AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
+
//////////////////////////////////////////////////////////////////////////
// Opened files collector.
//////////////////////////////////////////////////////////////////////////
@@ -339,5 +347,34 @@ namespace AZ::IO
// [LYN-2376] Remove once legacy slice support is removed
LevelPackOpenEvent m_levelOpenEvent;
LevelPackCloseEvent m_levelCloseEvent;
+
+ // If pak files are loaded before the serialization and bundling system
+ // are ready to go, their asset catalogs can't be loaded.
+ // In this case, cache information about those archives,
+ // and attempt to load the catalogs later, when the required systems are enabled.
+ struct ArchivesWithCatalogsToLoad
+ {
+ ArchivesWithCatalogsToLoad(
+ AZStd::string_view fullPath,
+ AZStd::string_view bindRoot,
+ int flags,
+ AZ::IO::PathView nextBundle,
+ AZ::IO::Path strFileName)
+ : m_fullPath(fullPath)
+ , m_bindRoot(bindRoot)
+ , m_flags(flags)
+ , m_nextBundle(nextBundle)
+ , m_strFileName(strFileName)
+ {
+ }
+
+ AZ::IO::Path m_strFileName;
+ AZStd::string m_fullPath;
+ AZStd::string m_bindRoot;
+ AZ::IO::PathView m_nextBundle;
+ int m_flags;
+ };
+
+ AZStd::vector m_archivesWithCatalogsToLoad;
};
}
diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp
index 68c4b00243..bc109b73c2 100644
--- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp
@@ -323,6 +323,13 @@ namespace AzFramework
return localZ;
}
+ void TransformComponent::SetWorldRotation(const AZ::Vector3& eulerAnglesRadian)
+ {
+ AZ::Transform newWorldTransform = m_worldTM;
+ newWorldTransform.SetRotation(AZ::Quaternion::CreateFromEulerAnglesRadians(eulerAnglesRadian));
+ SetWorldTM(newWorldTransform);
+ }
+
void TransformComponent::SetWorldRotationQuaternion(const AZ::Quaternion& quaternion)
{
AZ::Transform newWorldTransform = m_worldTM;
diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h
index ac282b4d49..2375f28ed1 100644
--- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h
+++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.h
@@ -108,6 +108,7 @@ namespace AzFramework
float GetLocalZ() override;
// Rotation modifiers
+ void SetWorldRotation(const AZ::Vector3& eulerAnglesRadian) override;
void SetWorldRotationQuaternion(const AZ::Quaternion& quaternion) override;
AZ::Vector3 GetWorldRotation() override;
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h b/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h
index 147ff7f0b8..74e2459ab6 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Buses/Requests/InputDeviceRequestBus.h
@@ -229,17 +229,13 @@ namespace AzFramework
//! Alias for the EBus implementation of this interface
using Bus = AZ::EBus>;
- ////////////////////////////////////////////////////////////////////////////////////////////
- //! Alias for the function type used to create the custom implementations
- using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
-
////////////////////////////////////////////////////////////////////////////////////////////
//! 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 SetCustomImplementation(CreateFunctionType createFunction) = 0;
+ //! \param[in] implementationFactory Pointer to the function that creates the implementation.
+ virtual void SetCustomImplementation(typename InputDeviceType::ImplementationFactory implementationFactory) = 0;
};
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -267,18 +263,14 @@ namespace AzFramework
AZ_DISABLE_COPY_MOVE(InputDeviceImplementationRequestHandler);
protected:
- ////////////////////////////////////////////////////////////////////////////////////////////
- //! Alias for the function type used to create the custom implementations
- using CreateFunctionType = typename InputDeviceType::Implementation*(*)(InputDeviceType&);
-
////////////////////////////////////////////////////////////////////////////////////////////
//! \ref InputDeviceImplementationRequest::SetCustomImplementation
- AZ_INLINE void SetCustomImplementation(CreateFunctionType createFunction) override
+ AZ_INLINE void SetCustomImplementation(typename InputDeviceType::ImplementationFactory implementationFactory) override
{
AZStd::unique_ptr newImplementation;
- if (createFunction)
+ if (implementationFactory)
{
- newImplementation.reset(createFunction(m_inputDevice));
+ newImplementation.reset(implementationFactory(m_inputDevice));
}
m_inputDevice.SetImplementation(AZStd::move(newImplementation));
}
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp
index 51aa008519..9759a95733 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp
@@ -94,7 +94,14 @@ namespace AzFramework
////////////////////////////////////////////////////////////////////////////////////////////////
InputDeviceGamepad::InputDeviceGamepad(AZ::u32 index)
- : InputDevice(InputDeviceId(Name, index))
+ : InputDeviceGamepad(InputDeviceId(Name, index)) // Delegated constructor
+ {
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ InputDeviceGamepad::InputDeviceGamepad(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory)
+ : InputDevice(inputDeviceId)
, m_allChannelsById()
, m_buttonChannelsById()
, m_triggerChannelsById()
@@ -144,8 +151,8 @@ namespace AzFramework
m_thumbStickDirectionChannelsById[channelId] = channel;
}
- // Create the platform specific implementation
- m_pimpl.reset(Implementation::Create(*this));
+ // Create the platform specific or custom implementation
+ m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the haptic feedback request bus
InputHapticFeedbackRequestBus::Handler::BusConnect(GetInputDeviceId());
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h
index 286b4f0df3..7be498830b 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h
@@ -182,6 +182,14 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Foward declare the internal Implementation class so it can be passed into the constructor
+ class Implementation;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Alias for the function type used to create a custom implementation for this input device
+ using ImplementationFactory = Implementation*(InputDeviceGamepad&);
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
explicit InputDeviceGamepad();
@@ -191,6 +199,13 @@ namespace AzFramework
//! \param[in] index Index of the game-pad device
explicit InputDeviceGamepad(AZ::u32 index);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Constructor
+ //! \param[in] inputDeviceId Id of the input device
+ //! \param[in] implementationFactory Optional override of the default Implementation::Create
+ explicit InputDeviceGamepad(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory = &Implementation::Create);
+
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
AZ_DISABLE_COPY_MOVE(InputDeviceGamepad);
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp
index d1117ea895..2a76cc6e1b 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp
@@ -182,8 +182,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- InputDeviceKeyboard::InputDeviceKeyboard(AzFramework::InputDeviceId id)
- : InputDevice(id)
+ InputDeviceKeyboard::InputDeviceKeyboard(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory)
+ : InputDevice(inputDeviceId)
, m_modifierKeyStates(AZStd::make_shared())
, m_allChannelsById()
, m_keyChannelsById()
@@ -203,8 +204,8 @@ namespace AzFramework
m_keyChannelsById[channelId] = channel;
}
- // Create the platform specific implementation
- m_pimpl.reset(Implementation::Create(*this));
+ // Create the platform specific or custom implementation
+ m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the text entry request bus
InputTextEntryRequestBus::Handler::BusConnect(GetInputDeviceId());
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h
index e3c21ec326..c0c2f5d92b 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h
@@ -370,9 +370,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Foward declare the internal Implementation class so it can be passed into the constructor
+ class Implementation;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Alias for the function type used to create a custom implementation for this input device
+ using ImplementationFactory = Implementation*(InputDeviceKeyboard&);
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
- InputDeviceKeyboard(AzFramework::InputDeviceId id = Id);
+ //! \param[in] inputDeviceId Optional override of the default input device id
+ //! \param[in] implementationFactory Optional override of the default Implementation::Create
+ explicit InputDeviceKeyboard(const InputDeviceId& inputDeviceId = Id,
+ ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp
index c144f63d2c..d4057bc5d3 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp
@@ -60,8 +60,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- InputDeviceMotion::InputDeviceMotion()
- : InputDevice(Id)
+ InputDeviceMotion::InputDeviceMotion(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory)
+ : InputDevice(inputDeviceId)
, m_allChannelsById()
, m_accelerationChannelsById()
, m_rotationRateChannelsById()
@@ -107,8 +108,8 @@ namespace AzFramework
m_orientationChannelsById[channelId] = channel;
}
- // Create the platform specific implementation
- m_pimpl.reset(Implementation::Create(*this));
+ // Create the platform specific or custom implementation
+ m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the motion sensor request bus
InputMotionSensorRequestBus::Handler::BusConnect(GetInputDeviceId());
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h
index 872bd1cfa0..f0fc976963 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h
@@ -126,9 +126,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Foward declare the internal Implementation class so it can be passed into the constructor
+ class Implementation;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Alias for the function type used to create a custom implementation for this input device
+ using ImplementationFactory = Implementation*(InputDeviceMotion&);
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
- InputDeviceMotion();
+ //! \param[in] inputDeviceId Optional override of the default input device id
+ //! \param[in] implementationFactory Optional override of the default Implementation::Create
+ explicit InputDeviceMotion(const InputDeviceId& inputDeviceId = Id,
+ ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp
index e9af4cc4ce..39504d9352 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp
@@ -67,8 +67,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- InputDeviceMouse::InputDeviceMouse(AzFramework::InputDeviceId id)
- : InputDevice(id)
+ InputDeviceMouse::InputDeviceMouse(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory)
+ : InputDevice(inputDeviceId)
, m_allChannelsById()
, m_buttonChannelsById()
, m_movementChannelsById()
@@ -97,8 +98,8 @@ namespace AzFramework
m_cursorPositionChannel = aznew InputChannelDeltaWithSharedPosition2D(SystemCursorPosition, *this, m_cursorPositionData2D);
m_allChannelsById[SystemCursorPosition] = m_cursorPositionChannel;
- // Create the platform specific implementation
- m_pimpl.reset(Implementation::Create(*this));
+ // Create the platform specific or custom implementation
+ m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the system cursor request bus
InputSystemCursorRequestBus::Handler::BusConnect(GetInputDeviceId());
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h
index 3b35e03f1b..3c519a3edb 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h
@@ -122,9 +122,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Foward declare the internal Implementation class so it can be passed into the constructor
+ class Implementation;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Alias for the function type used to create a custom implementation for this input device
+ using ImplementationFactory = Implementation*(InputDeviceMouse&);
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
- explicit InputDeviceMouse(AzFramework::InputDeviceId id = Id);
+ //! \param[in] inputDeviceId Optional override of the default input device id
+ //! \param[in] implementationFactory Optional override of the default Implementation::Create
+ explicit InputDeviceMouse(const InputDeviceId& inputDeviceId = Id,
+ ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp
index be850e9289..2695e3bb08 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp
@@ -59,8 +59,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- InputDeviceTouch::InputDeviceTouch()
- : InputDevice(Id)
+ InputDeviceTouch::InputDeviceTouch(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory)
+ : InputDevice(inputDeviceId)
, m_allChannelsById()
, m_touchChannelsById()
, m_pimpl(nullptr)
@@ -75,8 +76,8 @@ namespace AzFramework
m_touchChannelsById[channelId] = channel;
}
- // Create the platform specific implementation
- m_pimpl.reset(Implementation::Create(*this));
+ // Create the platform specific or custom implementation
+ m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
}
////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h
index d21834c22a..12b8aded4b 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h
@@ -77,9 +77,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Foward declare the internal Implementation class so it can be passed into the constructor
+ class Implementation;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Alias for the function type used to create a custom implementation for this input device
+ using ImplementationFactory = Implementation*(InputDeviceTouch&);
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
- InputDeviceTouch();
+ //! \param[in] inputDeviceId Optional override of the default input device id
+ //! \param[in] implementationFactory Optional override of the default Implementation::Create
+ explicit InputDeviceTouch(const InputDeviceId& inputDeviceId = Id,
+ ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp
index f3024f11ab..bcbdeaa478 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp
@@ -51,8 +51,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- InputDeviceVirtualKeyboard::InputDeviceVirtualKeyboard()
- : InputDevice(Id)
+ InputDeviceVirtualKeyboard::InputDeviceVirtualKeyboard(const InputDeviceId& inputDeviceId,
+ ImplementationFactory implementationFactory)
+ : InputDevice(inputDeviceId)
, m_allChannelsById()
, m_pimpl()
, m_implementationRequestHandler(*this)
@@ -65,8 +66,8 @@ namespace AzFramework
m_commandChannelsById[channelId] = channel;
}
- // Create the platform specific implementation
- m_pimpl.reset(Implementation::Create(*this));
+ // Create the platform specific or custom implementation
+ m_pimpl.reset(implementationFactory ? implementationFactory(*this) : nullptr);
// Connect to the text entry request bus
InputTextEntryRequestBus::Handler::BusConnect(GetInputDeviceId());
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h
index 6f62c3ec61..abe1312733 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h
@@ -69,9 +69,20 @@ namespace AzFramework
// Reflection
static void Reflect(AZ::ReflectContext* context);
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ // Foward declare the internal Implementation class so it can be passed into the constructor
+ class Implementation;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ //! Alias for the function type used to create a custom implementation for this input device
+ using ImplementationFactory = Implementation*(InputDeviceVirtualKeyboard&);
+
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
- InputDeviceVirtualKeyboard();
+ //! \param[in] inputDeviceId Optional override of the default input device id
+ //! \param[in] implementationFactory Optional override of the default Implementation::Create
+ explicit InputDeviceVirtualKeyboard(const InputDeviceId& inputDeviceId = Id,
+ ImplementationFactory implementationFactory = &Implementation::Create);
////////////////////////////////////////////////////////////////////////////////////////////
// Disable copying
diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h
index c657e0edc7..ccf9acdf8b 100644
--- a/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h
+++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/IMatchmakingRequests.h
@@ -24,17 +24,17 @@ namespace AzFramework
IMatchmakingRequests() = default;
virtual ~IMatchmakingRequests() = default;
- // Registers a player's acceptance or rejection of a proposed matchmaking.
- // @param acceptMatchRequest The request of AcceptMatch operation
+ //! Registers a player's acceptance or rejection of a proposed matchmaking.
+ //! @param acceptMatchRequest The request of AcceptMatch operation
virtual void AcceptMatch(const AcceptMatchRequest& acceptMatchRequest) = 0;
- // Create a game match for a group of players.
- // @param startMatchmakingRequest The request of StartMatchmaking operation
- // @return A unique identifier for a matchmaking ticket
+ //! Create a game match for a group of players.
+ //! @param startMatchmakingRequest The request of StartMatchmaking operation
+ //! @return A unique identifier for a matchmaking ticket
virtual AZStd::string StartMatchmaking(const StartMatchmakingRequest& startMatchmakingRequest) = 0;
- // Cancels a matchmaking ticket that is currently being processed.
- // @param stopMatchmakingRequest The request of StopMatchmaking operation
+ //! Cancels a matchmaking ticket that is currently being processed.
+ //! @param stopMatchmakingRequest The request of StopMatchmaking operation
virtual void StopMatchmaking(const StopMatchmakingRequest& stopMatchmakingRequest) = 0;
};
@@ -48,16 +48,16 @@ namespace AzFramework
IMatchmakingAsyncRequests() = default;
virtual ~IMatchmakingAsyncRequests() = default;
- // AcceptMatch Async
- // @param acceptMatchRequest The request of AcceptMatch operation
+ //! AcceptMatch Async
+ //! @param acceptMatchRequest The request of AcceptMatch operation
virtual void AcceptMatchAsync(const AcceptMatchRequest& acceptMatchRequest) = 0;
- // StartMatchmaking Async
- // @param startMatchmakingRequest The request of StartMatchmaking operation
+ //! StartMatchmaking Async
+ //! @param startMatchmakingRequest The request of StartMatchmaking operation
virtual void StartMatchmakingAsync(const StartMatchmakingRequest& startMatchmakingRequest) = 0;
- // StopMatchmaking Async
- // @param stopMatchmakingRequest The request of StopMatchmaking operation
+ //! StopMatchmaking Async
+ //! @param stopMatchmakingRequest The request of StopMatchmaking operation
virtual void StopMatchmakingAsync(const StopMatchmakingRequest& stopMatchmakingRequest) = 0;
};
@@ -76,14 +76,14 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
- // OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes
+ //! OnAcceptMatchAsyncComplete is fired once AcceptMatchAsync completes
virtual void OnAcceptMatchAsyncComplete() = 0;
- // OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes
- // @param matchmakingTicketId The unique identifier for the matchmaking ticket
+ //! OnStartMatchmakingAsyncComplete is fired once StartMatchmakingAsync completes
+ //! @param matchmakingTicketId The unique identifier for the matchmaking ticket
virtual void OnStartMatchmakingAsyncComplete(const AZStd::string& matchmakingTicketId) = 0;
- // OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes
+ //! OnStopMatchmakingAsyncComplete is fired once StopMatchmakingAsync completes
virtual void OnStopMatchmakingAsyncComplete() = 0;
};
using MatchmakingAsyncRequestNotificationBus = AZ::EBus;
diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h
index aa19b94b4a..0ec52c7215 100644
--- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h
+++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingNotifications.h
@@ -29,17 +29,17 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
- // OnMatchAcceptance is fired when match is found and pending on acceptance
- // Use this notification to accept found match
+ //! OnMatchAcceptance is fired when match is found and pending on acceptance
+ //! Use this notification to accept found match
virtual void OnMatchAcceptance() = 0;
- // OnMatchComplete is fired when match is complete
+ //! OnMatchComplete is fired when match is complete
virtual void OnMatchComplete() = 0;
- // OnMatchError is fired when match is processed with error
+ //! OnMatchError is fired when match is processed with error
virtual void OnMatchError() = 0;
- // OnMatchFailure is fired when match is failed to complete
+ //! OnMatchFailure is fired when match is failed to complete
virtual void OnMatchFailure() = 0;
};
using MatchmakingNotificationBus = AZ::EBus;
diff --git a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h
index 9169a83588..5f5dcc0643 100644
--- a/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h
+++ b/Code/Framework/AzFramework/AzFramework/Matchmaking/MatchmakingRequests.h
@@ -29,11 +29,11 @@ namespace AzFramework
AcceptMatchRequest() = default;
virtual ~AcceptMatchRequest() = default;
- // Player response to accept or reject match
+ //! Player response to accept or reject match
bool m_acceptMatch;
- // A list of unique identifiers for players delivering the response
+ //! A list of unique identifiers for players delivering the response
AZStd::vector m_playerIds;
- // A unique identifier for a matchmaking ticket
+ //! A unique identifier for a matchmaking ticket
AZStd::string m_ticketId;
};
@@ -47,7 +47,7 @@ namespace AzFramework
StartMatchmakingRequest() = default;
virtual ~StartMatchmakingRequest() = default;
- // A unique identifier for a matchmaking ticket
+ //! A unique identifier for a matchmaking ticket
AZStd::string m_ticketId;
};
@@ -61,7 +61,7 @@ namespace AzFramework
StopMatchmakingRequest() = default;
virtual ~StopMatchmakingRequest() = default;
- // A unique identifier for a matchmaking ticket
+ //! A unique identifier for a matchmaking ticket
AZStd::string m_ticketId;
};
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp
index d2f74510e5..0a0e1bb8e3 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.cpp
@@ -10,6 +10,7 @@
#include
#include
+#include
namespace AzPhysics
{
@@ -28,6 +29,71 @@ namespace AzPhysics
->Field("ChildLocalPosition", &JointConfiguration::m_childLocalPosition)
->Field("StartSimulationEnabled", &JointConfiguration::m_startSimulationEnabled)
;
+
+ if (auto* editContext = serializeContext->GetEditContext())
+ {
+ editContext->Class("Joint Configuration", "Joint configuration.")
+ ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+ ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+ ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_parentLocalRotation,
+ "Parent local rotation", "Parent joint frame relative to parent body.")
+ ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetParentLocalRotationVisibility)
+ ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_parentLocalPosition,
+ "Parent local position", "Joint position relative to parent body.")
+ ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetParentLocalPositionVisibility)
+ ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_childLocalRotation,
+ "Child local rotation", "Child joint frame relative to child body.")
+ ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetChildLocalRotationVisibility)
+ ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_childLocalPosition,
+ "Child local position", "Joint position relative to child body.")
+ ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetChildLocalPositionVisibility)
+ ->DataElement(AZ::Edit::UIHandlers::Default, &JointConfiguration::m_startSimulationEnabled,
+ "Start simulation enabled", "When active, the joint will be enabled when the simulation begins.")
+ ->Attribute(AZ::Edit::Attributes::Visibility, &JointConfiguration::GetStartSimulationEnabledVisibility)
+ ;
+ }
}
}
-}
+
+ AZ::Crc32 JointConfiguration::GetPropertyVisibility(JointConfiguration::PropertyVisibility property) const
+ {
+ return (m_propertyVisibilityFlags & property) != 0 ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
+ }
+
+ void JointConfiguration::SetPropertyVisibility(JointConfiguration::PropertyVisibility property, bool isVisible)
+ {
+ if (isVisible)
+ {
+ m_propertyVisibilityFlags |= property;
+ }
+ else
+ {
+ m_propertyVisibilityFlags &= ~property;
+ }
+ }
+
+ AZ::Crc32 JointConfiguration::GetParentLocalRotationVisibility() const
+ {
+ return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ParentLocalRotation);
+ }
+
+ AZ::Crc32 JointConfiguration::GetParentLocalPositionVisibility() const
+ {
+ return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ParentLocalPosition);
+ }
+
+ AZ::Crc32 JointConfiguration::GetChildLocalRotationVisibility() const
+ {
+ return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ChildLocalRotation);
+ }
+
+ AZ::Crc32 JointConfiguration::GetChildLocalPositionVisibility() const
+ {
+ return GetPropertyVisibility(JointConfiguration::PropertyVisibility::ChildLocalPosition);
+ }
+
+ AZ::Crc32 JointConfiguration::GetStartSimulationEnabledVisibility() const
+ {
+ return GetPropertyVisibility(JointConfiguration::PropertyVisibility::StartSimulationEnabled);
+ }
+} // namespace AzPhysics
diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h
index ff9bfb5bea..2a246692d7 100644
--- a/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h
+++ b/Code/Framework/AzFramework/AzFramework/Physics/Configuration/JointConfiguration.h
@@ -31,6 +31,25 @@ namespace AzPhysics
JointConfiguration() = default;
virtual ~JointConfiguration() = default;
+ // Visibility helpers for use in the Editor when reflected.
+ enum PropertyVisibility : AZ::u8
+ {
+ ParentLocalRotation = 1 << 0, //!< Whether the parent local rotation is visible.
+ ParentLocalPosition = 1 << 1, //!< Whether the parent local position is visible.
+ ChildLocalRotation = 1 << 2, //!< Whether the child local rotation is visible.
+ ChildLocalPosition = 1 << 3, //!< Whether the child local position is visible.
+ StartSimulationEnabled = 1 << 4 //!< Whether the start simulation enabled setting is visible.
+ };
+
+ AZ::Crc32 GetPropertyVisibility(PropertyVisibility property) const;
+ void SetPropertyVisibility(PropertyVisibility property, bool isVisible);
+
+ AZ::Crc32 GetParentLocalRotationVisibility() const;
+ AZ::Crc32 GetParentLocalPositionVisibility() const;
+ AZ::Crc32 GetChildLocalRotationVisibility() const;
+ AZ::Crc32 GetChildLocalPositionVisibility() const;
+ AZ::Crc32 GetStartSimulationEnabledVisibility() const;
+
// Entity/object association.
void* m_customUserData = nullptr;
@@ -40,8 +59,11 @@ namespace AzPhysics
AZ::Quaternion m_childLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Child joint frame relative to child body.
AZ::Vector3 m_childLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to child body.
bool m_startSimulationEnabled = true;
-
+
// For debugging/tracking purposes only.
AZStd::string m_debugName;
+
+ // Default all visibility settings to invisible, since most joint configurations don't need to display these.
+ AZ::u8 m_propertyVisibilityFlags = 0;
};
}
diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h b/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h
index 065d6bb9d5..188ea7b994 100644
--- a/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h
+++ b/Code/Framework/AzFramework/AzFramework/Session/ISessionHandlingRequests.h
@@ -18,16 +18,16 @@ namespace AzFramework
//! The properties for handling join session request.
struct SessionConnectionConfig
{
- // A unique identifier for registered player in session.
+ //! A unique identifier for registered player in session.
AZStd::string m_playerSessionId;
- // The DNS identifier assigned to the instance that is running the session.
+ //! The DNS identifier assigned to the instance that is running the session.
AZStd::string m_dnsName;
- // The IP address of the session.
+ //! The IP address of the session.
AZStd::string m_ipAddress;
- // The port number for the session.
+ //! The port number for the session.
uint16_t m_port = 0;
};
@@ -35,10 +35,10 @@ namespace AzFramework
//! The properties for handling player connect/disconnect
struct PlayerConnectionConfig
{
- // A unique identifier for player connection.
+ //! A unique identifier for player connection.
uint32_t m_playerConnectionId = 0;
- // A unique identifier for registered player in session.
+ //! A unique identifier for registered player in session.
AZStd::string m_playerSessionId;
};
@@ -51,12 +51,12 @@ namespace AzFramework
ISessionHandlingClientRequests() = default;
virtual ~ISessionHandlingClientRequests() = default;
- // Request the player join session
- // @param sessionConnectionConfig The required properties to handle the player join session process
- // @return The result of player join session process
+ //! Request the player join session
+ //! @param sessionConnectionConfig The required properties to handle the player join session process
+ //! @return The result of player join session process
virtual bool RequestPlayerJoinSession(const SessionConnectionConfig& sessionConnectionConfig) = 0;
- // Request the connected player leave session
+ //! Request the connected player leave session
virtual void RequestPlayerLeaveSession() = 0;
};
@@ -69,26 +69,26 @@ namespace AzFramework
ISessionHandlingProviderRequests() = default;
virtual ~ISessionHandlingProviderRequests() = default;
- // Handle the destroy session process
+ //! Handle the destroy session process
virtual void HandleDestroySession() = 0;
- // Validate the player join session process
- // @param playerConnectionConfig The required properties to validate the player join session process
- // @return The result of player join session validation
+ //! Validate the player join session process
+ //! @param playerConnectionConfig The required properties to validate the player join session process
+ //! @return The result of player join session validation
virtual bool ValidatePlayerJoinSession(const PlayerConnectionConfig& playerConnectionConfig) = 0;
- // Handle the player leave session process
- // @param playerConnectionConfig The required properties to handle the player leave session process
+ //! Handle the player leave session process
+ //! @param playerConnectionConfig The required properties to handle the player leave session process
virtual void HandlePlayerLeaveSession(const PlayerConnectionConfig& playerConnectionConfig) = 0;
- // Retrieves the file location of a pem-encoded TLS certificate for Client to Server communication
- // @return If successful, returns the file location of TLS certificate file; if not successful, returns
- // empty string.
+ //! Retrieves the file location of a pem-encoded TLS certificate for Client to Server communication
+ //! @return If successful, returns the file location of TLS certificate file; if not successful, returns
+ //! empty string.
virtual AZ::IO::Path GetExternalSessionCertificate() = 0;
- // Retrieves the file location of a pem-encoded TLS certificate for Server to Server communication
- // @return If successful, returns the file location of TLS certificate file; if not successful, returns
- // empty string.
+ //! Retrieves the file location of a pem-encoded TLS certificate for Server to Server communication
+ //! @return If successful, returns the file location of TLS certificate file; if not successful, returns
+ //! empty string.
virtual AZ::IO::Path GetInternalSessionCertificate() = 0;
};
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h b/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h
index bdc3fe1444..8b985a3187 100644
--- a/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h
+++ b/Code/Framework/AzFramework/AzFramework/Session/ISessionRequests.h
@@ -25,22 +25,22 @@ namespace AzFramework
ISessionRequests() = default;
virtual ~ISessionRequests() = default;
- // Create a session for players to find and join.
- // @param createSessionRequest The request of CreateSession operation
- // @return The request id if session creation request succeeds; empty if it fails
+ //! Create a session for players to find and join.
+ //! @param createSessionRequest The request of CreateSession operation
+ //! @return The request id if session creation request succeeds; empty if it fails
virtual AZStd::string CreateSession(const CreateSessionRequest& createSessionRequest) = 0;
- // Retrieve all active sessions that match the given search criteria and sorted in specific order.
- // @param searchSessionsRequest The request of SearchSessions operation
- // @return The response of SearchSessions operation
+ //! Retrieve all active sessions that match the given search criteria and sorted in specific order.
+ //! @param searchSessionsRequest The request of SearchSessions operation
+ //! @return The response of SearchSessions operation
virtual SearchSessionsResponse SearchSessions(const SearchSessionsRequest& searchSessionsRequest) const = 0;
- // Reserve an open player slot in a session, and perform connection from client to server.
- // @param joinSessionRequest The request of JoinSession operation
- // @return True if joining session succeeds; False otherwise
+ //! Reserve an open player slot in a session, and perform connection from client to server.
+ //! @param joinSessionRequest The request of JoinSession operation
+ //! @return True if joining session succeeds; False otherwise
virtual bool JoinSession(const JoinSessionRequest& joinSessionRequest) = 0;
- // Disconnect player from session.
+ //! Disconnect player from session.
virtual void LeaveSession() = 0;
};
@@ -54,19 +54,19 @@ namespace AzFramework
ISessionAsyncRequests() = default;
virtual ~ISessionAsyncRequests() = default;
- // CreateSession Async
- // @param createSessionRequest The request of CreateSession operation
+ //! CreateSession Async
+ //! @param createSessionRequest The request of CreateSession operation
virtual void CreateSessionAsync(const CreateSessionRequest& createSessionRequest) = 0;
- // SearchSessions Async
- // @param searchSessionsRequest The request of SearchSessions operation
+ //! SearchSessions Async
+ //! @param searchSessionsRequest The request of SearchSessions operation
virtual void SearchSessionsAsync(const SearchSessionsRequest& searchSessionsRequest) const = 0;
- // JoinSession Async
- // @param joinSessionRequest The request of JoinSession operation
+ //! JoinSession Async
+ //! @param joinSessionRequest The request of JoinSession operation
virtual void JoinSessionAsync(const JoinSessionRequest& joinSessionRequest) = 0;
- // LeaveSession Async
+ //! LeaveSession Async
virtual void LeaveSessionAsync() = 0;
};
@@ -85,19 +85,19 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
- // OnCreateSessionAsyncComplete is fired once CreateSessionAsync completes
- // @param createSessionResponse The request id if session creation request succeeds; empty if it fails
+ //! OnCreateSessionAsyncComplete is fired once CreateSessionAsync completes
+ //! @param createSessionResponse The request id if session creation request succeeds; empty if it fails
virtual void OnCreateSessionAsyncComplete(const AZStd::string& createSessionReponse) = 0;
- // OnSearchSessionsAsyncComplete is fired once SearchSessionsAsync completes
- // @param searchSessionsResponse The response of SearchSessions call
+ //! OnSearchSessionsAsyncComplete is fired once SearchSessionsAsync completes
+ //! @param searchSessionsResponse The response of SearchSessions call
virtual void OnSearchSessionsAsyncComplete(const SearchSessionsResponse& searchSessionsResponse) = 0;
- // OnJoinSessionAsyncComplete is fired once JoinSessionAsync completes
- // @param joinSessionsResponse True if joining session succeeds; False otherwise
+ //! OnJoinSessionAsyncComplete is fired once JoinSessionAsync completes
+ //! @param joinSessionsResponse True if joining session succeeds; False otherwise
virtual void OnJoinSessionAsyncComplete(bool joinSessionsResponse) = 0;
- // OnLeaveSessionAsyncComplete is fired once LeaveSessionAsync completes
+ //! OnLeaveSessionAsyncComplete is fired once LeaveSessionAsync completes
virtual void OnLeaveSessionAsyncComplete() = 0;
};
using SessionAsyncRequestNotificationBus = AZ::EBus;
diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h
index 45e40c2f29..f951cf58fa 100644
--- a/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h
+++ b/Code/Framework/AzFramework/AzFramework/Session/SessionConfig.h
@@ -24,46 +24,46 @@ namespace AzFramework
SessionConfig() = default;
virtual ~SessionConfig() = default;
- // A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.
+ //! A time stamp indicating when this session was created. Format is a number expressed in Unix time as milliseconds.
uint64_t m_creationTime = 0;
- // A time stamp indicating when this data object was terminated. Same format as creation time.
+ //! A time stamp indicating when this data object was terminated. Same format as creation time.
uint64_t m_terminationTime = 0;
- // A unique identifier for a player or entity creating the session.
+ //! A unique identifier for a player or entity creating the session.
AZStd::string m_creatorId;
- // A collection of custom properties for a session.
+ //! A collection of custom properties for a session.
AZStd::unordered_map m_sessionProperties;
- // The matchmaking process information that was used to create the session.
+ //! The matchmaking process information that was used to create the session.
AZStd::string m_matchmakingData;
- // A unique identifier for the session.
+ //! A unique identifier for the session.
AZStd::string m_sessionId;
- // A descriptive label that is associated with a session.
+ //! A descriptive label that is associated with a session.
AZStd::string m_sessionName;
- // The DNS identifier assigned to the instance that is running the session.
+ //! The DNS identifier assigned to the instance that is running the session.
AZStd::string m_dnsName;
- // The IP address of the session.
+ //! The IP address of the session.
AZStd::string m_ipAddress;
- // The port number for the session.
+ //! The port number for the session.
uint16_t m_port = 0;
- // The maximum number of players that can be connected simultaneously to the session.
+ //! The maximum number of players that can be connected simultaneously to the session.
uint64_t m_maxPlayer = 0;
- // Number of players currently in the session.
+ //! Number of players currently in the session.
uint64_t m_currentPlayer = 0;
- // Current status of the session.
+ //! Current status of the session.
AZStd::string m_status;
- // Provides additional information about session status.
+ //! Provides additional information about session status.
AZStd::string m_statusReason;
};
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h b/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h
index 2213343aa2..cf1382aeba 100644
--- a/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h
+++ b/Code/Framework/AzFramework/AzFramework/Session/SessionNotifications.h
@@ -29,42 +29,42 @@ namespace AzFramework
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
- // OnSessionHealthCheck is fired in health check process
- // Use this notification to perform any custom health check
- // @return True if OnSessionHealthCheck succeeds, false otherwise
+ //! OnSessionHealthCheck is fired in health check process
+ //! Use this notification to perform any custom health check
+ //! @return True if OnSessionHealthCheck succeeds, false otherwise
virtual bool OnSessionHealthCheck() = 0;
- // OnCreateSessionBegin is fired at the beginning of session creation process
- // Use this notification to perform any necessary configuration or initialization before
- // creating session
- // @param sessionConfig The properties to describe a session
- // @return True if OnCreateSessionBegin succeeds, false otherwise
+ //! OnCreateSessionBegin is fired at the beginning of session creation process
+ //! Use this notification to perform any necessary configuration or initialization before
+ //! creating session
+ //! @param sessionConfig The properties to describe a session
+ //! @return True if OnCreateSessionBegin succeeds, false otherwise
virtual bool OnCreateSessionBegin(const SessionConfig& sessionConfig) = 0;
- // OnCreateSessionEnd is fired at the end of session creation process
- // Use this notification to perform any follow-up operation after session is created and active
+ //! OnCreateSessionEnd is fired at the end of session creation process
+ //! Use this notification to perform any follow-up operation after session is created and active
virtual void OnCreateSessionEnd() = 0;
- // OnDestroySessionBegin is fired at the beginning of session termination process
- // Use this notification to perform any cleanup operation before destroying session,
- // like gracefully disconnect players, cleanup data, etc.
- // @return True if OnDestroySessionBegin succeeds, false otherwise
+ //! OnDestroySessionBegin is fired at the beginning of session termination process
+ //! Use this notification to perform any cleanup operation before destroying session,
+ //! like gracefully disconnect players, cleanup data, etc.
+ //! @return True if OnDestroySessionBegin succeeds, false otherwise
virtual bool OnDestroySessionBegin() = 0;
- // OnDestroySessionEnd is fired at the end of session termination process
- // Use this notification to perform any follow-up operation after session is destroyed,
- // like shutdown application process, etc.
+ //! OnDestroySessionEnd is fired at the end of session termination process
+ //! Use this notification to perform any follow-up operation after session is destroyed,
+ //! like shutdown application process, etc.
virtual void OnDestroySessionEnd() = 0;
- // OnUpdateSessionBegin is fired at the beginning of session update process
- // Use this notification to perform any configuration or initialization to handle
- // the session settings changing
- // @param sessionConfig The properties to describe a session
- // @param updateReason The reason for session update
+ //! OnUpdateSessionBegin is fired at the beginning of session update process
+ //! Use this notification to perform any configuration or initialization to handle
+ //! the session settings changing
+ //! @param sessionConfig The properties to describe a session
+ //! @param updateReason The reason for session update
virtual void OnUpdateSessionBegin(const SessionConfig& sessionConfig, const AZStd::string& updateReason) = 0;
- // OnUpdateSessionBegin is fired at the end of session update process
- // Use this notification to perform any follow-up operations after session is updated
+ //! OnUpdateSessionBegin is fired at the end of session update process
+ //! Use this notification to perform any follow-up operations after session is updated
virtual void OnUpdateSessionEnd() = 0;
};
using SessionNotificationBus = AZ::EBus;
diff --git a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h
index 1ae018e1ef..d806e6fefa 100644
--- a/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h
+++ b/Code/Framework/AzFramework/AzFramework/Session/SessionRequests.h
@@ -31,16 +31,16 @@ namespace AzFramework
CreateSessionRequest() = default;
virtual ~CreateSessionRequest() = default;
- // A unique identifier for a player or entity creating the session.
+ //! A unique identifier for a player or entity creating the session.
AZStd::string m_creatorId;
- // A collection of custom properties for a session.
+ //! A collection of custom properties for a session.
AZStd::unordered_map m_sessionProperties;
- // A descriptive label that is associated with a session.
+ //! A descriptive label that is associated with a session.
AZStd::string m_sessionName;
- // The maximum number of players that can be connected simultaneously to the session.
+ //! The maximum number of players that can be connected simultaneously to the session.
uint64_t m_maxPlayer = 0;
};
@@ -54,17 +54,17 @@ namespace AzFramework
SearchSessionsRequest() = default;
virtual ~SearchSessionsRequest() = default;
- // String containing the search criteria for the session search. If no filter expression is included, the request returns results
- // for all active sessions.
+ //! String containing the search criteria for the session search. If no filter expression is included, the request returns results
+ //! for all active sessions.
AZStd::string m_filterExpression;
- // Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order.
+ //! Instructions on how to sort the search results. If no sort expression is included, the request returns results in random order.
AZStd::string m_sortExpression;
- // The maximum number of results to return.
+ //! The maximum number of results to return.
uint8_t m_maxResult = 0;
- // A token that indicates the start of the next sequential page of results.
+ //! A token that indicates the start of the next sequential page of results.
AZStd::string m_nextToken;
};
@@ -78,10 +78,10 @@ namespace AzFramework
SearchSessionsResponse() = default;
virtual ~SearchSessionsResponse() = default;
- // A collection of sessions that match the search criteria and sorted in specific order.
+ //! A collection of sessions that match the search criteria and sorted in specific order.
AZStd::vector m_sessionConfigs;
- // A token that indicates the start of the next sequential page of results.
+ //! A token that indicates the start of the next sequential page of results.
AZStd::string m_nextToken;
};
@@ -95,13 +95,13 @@ namespace AzFramework
JoinSessionRequest() = default;
virtual ~JoinSessionRequest() = default;
- // A unique identifier for the session.
+ //! A unique identifier for the session.
AZStd::string m_sessionId;
- // A unique identifier for a player. Player IDs are developer-defined.
+ //! A unique identifier for a player. Player IDs are developer-defined.
AZStd::string m_playerId;
- // Developer-defined information related to a player.
+ //! Developer-defined information related to a player.
AZStd::string m_playerData;
};
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp
index 57b37037ae..3bd0abab8d 100644
--- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp
+++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp
@@ -54,6 +54,7 @@ namespace AzFramework
RECT m_windowRectToRestoreOnFullScreenExit; //!< The position and size of the window to restore when exiting full screen.
UINT m_windowStyleToRestoreOnFullScreenExit; //!< The style(s) of the window to restore when exiting full screen.
bool m_isInBorderlessWindowFullScreenState = false; //!< Was a borderless window used to enter full screen state?
+ bool m_shouldEnterFullScreenStateOnActivate = false; //!< Should we enter full screen state when the window is activated?
using GetDpiForWindowType = UINT(HWND hwnd);
GetDpiForWindowType* m_getDpiFunction = nullptr;
@@ -249,6 +250,28 @@ namespace AzFramework
AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputCodeUnitUTF16Event, codeUnitUTF16);
break;
}
+ case WM_ACTIVATE:
+ {
+ // Alt-tabbing out of the app while it is in a full screen state does not
+ // work unless we explicitly exit the full screen state upon deactivation,
+ // in which case we want to enter full screen state again upon activation.
+ const bool windowIsNowInactive = (LOWORD(wParam) == WA_INACTIVE);
+ const bool windowFullScreenState = nativeWindowImpl->GetFullScreenState();
+ if (windowIsNowInactive &&
+ windowFullScreenState)
+ {
+ nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate = true;
+ nativeWindowImpl->SetFullScreenState(false);
+ }
+ else if (!windowIsNowInactive &&
+ !windowFullScreenState &&
+ nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate)
+ {
+ nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate = false;
+ nativeWindowImpl->SetFullScreenState(true);
+ }
+ break;
+ }
case WM_SYSKEYDOWN:
{
// Handle ALT+ENTER to toggle full screen unless exclsuive full screen
diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
index 0cce93d751..f0417d206e 100644
--- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
+++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp
@@ -45,6 +45,13 @@ namespace AzGameFramework
enginePakPath = AZ::IO::FixedMaxPath(AZ::Utils::GetExecutableDirectory()) / "engine.pak";
m_archive->OpenPack("@products@", enginePakPath.Native());
}
+
+ // By default, load all archives in the products folder.
+ // If you want to adjust this for your project, make sure that the archive containing
+ // the bootstrap for the settings registry is still loaded here, and any archives containing
+ // assets used early in startup, like default shaders, are loaded here.
+ constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed)
+ m_archive->OpenPacks(paksFolder);
}
GameApplication::~GameApplication()
@@ -82,7 +89,7 @@ namespace AzGameFramework
// Used the lowercase the platform name since the bootstrap.game...setreg is being loaded
// from the asset cache root where all the files are in lowercased from regardless of the filesystem case-sensitivity
- static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE "." AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER ".setreg";
+ static constexpr char filename[] = "bootstrap.game." AZ_BUILD_CONFIGURATION_TYPE ".setreg";
AZ::IO::FixedMaxPath cacheRootPath;
if (registry.Get(cacheRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder))
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp
index 8831bef89c..11fd1e60d8 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp
@@ -27,7 +27,6 @@ namespace AzQtComponents
setProperty("HasNoWindowDecorations", true);
setAttribute(Qt::WA_ShowWithoutActivating);
- setAttribute(Qt::WA_DeleteOnClose);
m_borderRadius = toastConfiguration.m_borderRadius;
if (m_borderRadius > 0)
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h
index 4343f37df4..81b1cb4055 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h
@@ -31,7 +31,6 @@ namespace AzQtComponents
{
Q_OBJECT
public:
- AZ_CLASS_ALLOCATOR(ToastNotification, AZ::SystemAllocator, 0);
ToastNotification(QWidget* parent, const ToastConfiguration& toastConfiguration);
virtual ~ToastNotification();
@@ -73,7 +72,7 @@ namespace AzQtComponents
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZStd::chrono::milliseconds m_fadeDuration;
- AZStd::unique_ptr m_ui;
+ QScopedPointer m_ui;
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
};
} // namespace AzQtComponents
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h
index 5ace9d1be2..2db374640e 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotificationConfiguration.h
@@ -27,7 +27,6 @@ namespace AzQtComponents
class AZ_QT_COMPONENTS_API ToastConfiguration
{
public:
- AZ_CLASS_ALLOCATOR(ToastConfiguration, AZ::SystemAllocator, 0);
ToastConfiguration(ToastType toastType, const QString& title, const QString& description);
bool m_closeOnClick = true;
diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp
index 06361ceee9..8ace8d0f40 100644
--- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp
+++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp
@@ -657,13 +657,18 @@ bool SpinBoxWatcher::handleMouseDragStepping(QAbstractSpinBox* spinBox, QEvent*
QPoint screenPos = mouseEvent->screenPos().toPoint();
const int xPos = screenPos.x();
int newXPos = xPos;
+ // cursor bounces on the left and right side of the screen
+ // looks like buggy behaviour so mouse cursor is wrapped
+ // around to the other side of the screen.
if (xPos >= screenRect.right())
{
- newXPos = screenRect.right() - 1;
+ // wraps mouse cursor around to the left side of the screen
+ newXPos = screenRect.left() + 1;
}
else if (xPos <= screenRect.left())
{
- newXPos = screenRect.left() + 1;
+ // wraps mouse cursor around to the right side of the screen
+ newXPos = screenRect.right() - 1;
}
if (newXPos != xPos)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h
index be93e1af1a..33b60f0f51 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h
@@ -40,7 +40,7 @@ namespace AzToolsFramework
bool isDisabledInSimMode = false; ///< set to true if the view pane should not be openable from level editor menu when editor is in simulation mode.
bool showOnToolsToolbar = false; ///< set to true if the view pane should create a button on the tools toolbar to open/close the pane
- QString toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
+ AZStd::string toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
};
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
index 67563aaf69..f203251407 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
@@ -426,6 +426,8 @@ namespace AzToolsFramework
->Property("showInMenu", BehaviorValueProperty(&ViewPaneOptions::showInMenu))
->Property("canHaveMultipleInstances", BehaviorValueProperty(&ViewPaneOptions::canHaveMultipleInstances))
->Property("isPreview", BehaviorValueProperty(&ViewPaneOptions::isPreview))
+ ->Property("showOnToolsToolbar", BehaviorValueProperty(&ViewPaneOptions::showOnToolsToolbar))
+ ->Property("toolbarIcon", BehaviorValueProperty(&ViewPaneOptions::toolbarIcon))
;
behaviorContext->EBus("EditorRequestBus")
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
index 483faf03c2..7da6f794d6 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
@@ -102,7 +102,7 @@ namespace AzToolsFramework
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AssetSystemBus::Handler::BusDisconnect();
- m_assetBrowserModel.release();
+ m_assetBrowserModel.reset();
EntryCache::DestroyInstance();
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
index 61b257a189..0a27a5cb90 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
@@ -26,8 +26,12 @@ namespace AzToolsFramework
AZ::Interface::Unregister(this);
}
- void ContainerEntitySystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
+ void ContainerEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
+ if (auto serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()->Version(1);
+ }
}
void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
index 44ff603c0c..16640f4edf 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
@@ -47,8 +47,12 @@ namespace AzToolsFramework
AZ::Interface::Unregister(this);
}
- void FocusModeSystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
+ void FocusModeSystemComponent::Reflect(AZ::ReflectContext* context)
{
+ if (auto serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()->Version(1);
+ }
}
void FocusModeSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp
index 574470ad6e..7ee20997f9 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp
@@ -210,8 +210,8 @@ namespace AzToolsFramework
m_enabled = enabled;
if (!enabled)
{
- // Send an internal focus change event to reset our input state to fresh if we're disabled.
- HandleFocusChange(nullptr);
+ // Clear input channels to reset our input state if we're disabled.
+ ClearInputChannels(nullptr);
}
}
@@ -246,7 +246,7 @@ namespace AzToolsFramework
if (eventType == QEvent::Type::MouseMove)
{
- // clear override cursor when moving outside of the viewport
+ // Clear override cursor when moving outside of the viewport
const auto* mouseEvent = static_cast(event);
if (m_overrideCursor && !m_sourceWidget->geometry().contains(m_sourceWidget->mapFromGlobal(mouseEvent->globalPos())))
{
@@ -255,6 +255,13 @@ namespace AzToolsFramework
}
}
+ // If the application state changes (e.g. we have alt-tabbed or minimized the
+ // main editor window) then ensure all input channels are cleared
+ if (eventType == QEvent::ApplicationStateChange)
+ {
+ ClearInputChannels(event);
+ }
+
// Only accept mouse & key release events that originate from an object that is not our target widget,
// as we don't want to erroneously intercept user input meant for another component.
if (object != m_sourceWidget && eventType != QEvent::Type::KeyRelease && eventType != QEvent::Type::MouseButtonRelease)
@@ -264,9 +271,6 @@ namespace AzToolsFramework
if (eventType == QEvent::FocusIn || eventType == QEvent::FocusOut)
{
- // If our focus changes, go ahead and reset all input devices.
- HandleFocusChange(event);
-
// If we focus in on the source widget and the mouse is contained in its
// bounds, refresh the cached cursor position to ensure it is up to date (this
// ensures cursor positions are refreshed correctly with context menu focus changes)
@@ -451,7 +455,7 @@ namespace AzToolsFramework
NotifyUpdateChannelIfNotIdle(cursorZChannel, wheelEvent);
}
- void QtEventToAzInputMapper::HandleFocusChange(QEvent* event)
+ void QtEventToAzInputMapper::ClearInputChannels(QEvent* event)
{
for (auto& channelData : m_channels)
{
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h
index 4cb391e63b..4c4e09ea05 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h
@@ -138,8 +138,9 @@ namespace AzToolsFramework
void HandleKeyEvent(QKeyEvent* keyEvent);
// Handles mouse wheel events.
void HandleWheelEvent(QWheelEvent* wheelEvent);
- // Handles focus change events.
- void HandleFocusChange(QEvent* event);
+
+ // Clear all input channels (set all channel states to 'ended').
+ void ClearInputChannels(QEvent* event);
// Populates m_keyMappings.
void InitializeKeyMappings();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
index a6a80e58d3..7c5a6ebb8a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
@@ -12,11 +12,12 @@
#include
#include
+#include
#include
#include
#include
-#include
#include
+#include
#include
#include
#include
@@ -565,6 +566,7 @@ namespace AzToolsFramework
parentId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
}
+ // If the parent entity isn't owned by a prefab instance, bail.
InstanceOptionalReference owningInstanceOfParentEntity = GetOwnerInstanceByEntityId(parentId);
if (!owningInstanceOfParentEntity)
{
@@ -572,6 +574,14 @@ namespace AzToolsFramework
"Cannot add entity because the owning instance of parent entity with id '%llu' could not be found.",
static_cast(parentId)));
}
+
+ // If the parent entity is a closed container, bail.
+ if (auto containerEntityInterface = AZ::Interface::Get(); !containerEntityInterface->IsContainerOpen(parentId))
+ {
+ return AZ::Failure(AZStd::string::format(
+ "Cannot add entity because the parent entity (id '%llu') is a closed container entity.",
+ static_cast(parentId)));
+ }
EntityAlias entityAlias = Instance::GenerateEntityAlias();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp
index a88711a9ed..277d3fa3c5 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp
@@ -129,7 +129,7 @@ namespace AzToolsFramework
ToastId ToastNotificationsView::CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration)
{
- AzQtComponents::ToastNotification* notification = aznew AzQtComponents::ToastNotification(parentWidget(), toastConfiguration);
+ AzQtComponents::ToastNotification* notification = new AzQtComponents::ToastNotification(this, toastConfiguration);
ToastId toastId = AZ::Entity::MakeId();
m_notifications[toastId] = notification;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
index 434a1d8303..13ec27c1b8 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -764,10 +765,21 @@ namespace AzToolsFramework
return canHandleData;
}
- bool EntityOutlinerListModel::CanDropMimeDataAssets(const QMimeData* data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex& /*parent*/) const
+ bool EntityOutlinerListModel::CanDropMimeDataAssets(
+ const QMimeData* data,
+ [[maybe_unused]] Qt::DropAction action,
+ [[maybe_unused]] int row,
+ [[maybe_unused]] int column,
+ const QModelIndex& parent) const
{
- using namespace AzToolsFramework;
-
+ // Disable dropping assets on closed container entities.
+ AZ::EntityId parentId = GetEntityFromIndex(parent);
+ if (auto containerEntityInterface = AZ::Interface::Get();
+ !containerEntityInterface->IsContainerOpen(parentId))
+ {
+ return false;
+ }
+
if (data->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType()))
{
return DecodeAssetMimeData(data);
@@ -788,8 +800,15 @@ namespace AzToolsFramework
return false;
}
+ // If the parent entity is a closed container, bail.
+ if (auto containerEntityInterface = AZ::Interface::Get();
+ !containerEntityInterface->IsContainerOpen(assignParentId))
+ {
+ return false;
+ }
+
// Source Files
- if (sourceFiles.size() > 0)
+ if (!sourceFiles.empty())
{
// Get position (center of viewport). If no viewport is available, (0,0,0) will be used.
AZ::Vector3 viewportCenterPosition = AZ::Vector3::CreateZero();
@@ -973,6 +992,12 @@ namespace AzToolsFramework
return false;
}
+ // If the new parent is a closed container, bail.
+ if (auto containerEntityInterface = AZ::Interface::Get(); !containerEntityInterface->IsContainerOpen(newParentId))
+ {
+ return false;
+ }
+
// Ignore entities not owned by the editor context. It is assumed that all entities belong
// to the same context since multiple selection doesn't span across views.
for (const AZ::EntityId& entityId : selectedEntityIds)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp
index 7f3b9e61fd..24b2c7466e 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp
@@ -1387,7 +1387,10 @@ namespace AzToolsFramework
QDataStream stream(&pixmapBytes, QIODevice::ReadOnly);
QPixmap pixmap;
stream >> pixmap;
- GUI->SetBrowseButtonIcon(pixmap);
+ if (!pixmap.isNull())
+ {
+ GUI->SetBrowseButtonIcon(pixmap);
+ }
}
}
}
@@ -1417,6 +1420,8 @@ namespace AzToolsFramework
}
else if (attrib == AZ_CRC_CE("ThumbnailIcon"))
{
+ GUI->SetCustomThumbnailEnabled(false);
+
AZStd::string iconPath;
if (attrValue->Read(iconPath) && !iconPath.empty())
{
@@ -1434,8 +1439,11 @@ namespace AzToolsFramework
QDataStream stream(&pixmapBytes, QIODevice::ReadOnly);
QPixmap pixmap;
stream >> pixmap;
- GUI->SetCustomThumbnailEnabled(true);
- GUI->SetCustomThumbnailPixmap(pixmap);
+ if (!pixmap.isNull())
+ {
+ GUI->SetCustomThumbnailEnabled(true);
+ GUI->SetCustomThumbnailPixmap(pixmap);
+ }
}
}
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp
index d8ddee6b76..0bbb898196 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/ThumbnailPropertyCtrl.cpp
@@ -67,16 +67,9 @@ namespace AzToolsFramework
void ThumbnailPropertyCtrl::SetThumbnailKey(Thumbnailer::SharedThumbnailKey key, const char* contextName)
{
- if (m_customThumbnailEnabled)
- {
- ClearThumbnail();
- }
- else
- {
- m_key = key;
- m_thumbnail->SetThumbnailKey(m_key, contextName);
- m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName);
- }
+ m_key = key;
+ m_thumbnail->SetThumbnailKey(m_key, contextName);
+ m_thumbnailEnlarged->SetThumbnailKey(m_key, contextName);
UpdateVisibility();
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h
index 55a6d614ea..fe54b5379b 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/InvalidClicks.h
@@ -80,8 +80,9 @@ namespace AzToolsFramework
private:
AZStd::string m_message; //!< Message to display for fading text.
- float m_opacity = 1.0f; //!< The opacity of the invalid click message.
- AzFramework::ScreenPoint m_invalidClickPosition; //!< The position to display the invalid click message.
+ float m_opacity = 0.0f; //!< The opacity of the invalid click message.
+ //! The position to display the invalid click message.
+ AzFramework::ScreenPoint m_invalidClickPosition = AzFramework::ScreenPoint(0, 0);
};
//! Interface to begin invalid click feedback (will run all added InvalidClick behaviors).
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp
index 5155de3087..0f79e3535d 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp
@@ -301,6 +301,7 @@ namespace AzToolsFramework::ViewportUi::Internal
HighlightBorderSize + ViewportUiOverlayMargin, HighlightBorderSize + ViewportUiOverlayMargin);
m_componentModeBorderText.setVisible(true);
m_componentModeBorderText.setText(borderTitle.c_str());
+ UpdateUiOverlayGeometry();
}
void ViewportUiDisplay::RemoveViewportBorder()
diff --git a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp
index 11a077f53c..1aa7b39593 100644
--- a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp
+++ b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.cpp
@@ -28,9 +28,12 @@ namespace UnitTest
return true;
}
- void BoundsTestComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
+ void BoundsTestComponent::Reflect(AZ::ReflectContext* context)
{
- // noop
+ if (auto serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()->Version(1);
+ }
}
void BoundsTestComponent::Activate()
diff --git a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h
index 1aabcfcd64..036f9c8798 100644
--- a/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h
+++ b/Code/Framework/AzToolsFramework/Tests/BoundsTestComponent.h
@@ -42,5 +42,4 @@ namespace UnitTest
AZ::Aabb GetWorldBounds() override;
AZ::Aabb GetLocalBounds() override;
};
-
} // namespace UnitTest
diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnAllEntitiesBenchmarks.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnAllEntitiesBenchmarks.cpp
new file mode 100644
index 0000000000..ecbbe10c39
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnAllEntitiesBenchmarks.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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
+ *
+ */
+#if defined(HAVE_BENCHMARK)
+
+#include
+#include
+#include
+
+namespace Benchmark
+{
+ using BM_SpawnAllEntities = BM_Spawnable;
+
+ BENCHMARK_DEFINE_F(BM_SpawnAllEntities, SingleEntitySpawnable_SpawnCallVariable)(::benchmark::State& state)
+ {
+ const uint64_t spawnAllEntitiesCallCount = aznumeric_cast(state.range());
+ const uint64_t entityCountInSourcePrefab = 1;
+
+ SetUpSpawnableAsset(entityCountInSourcePrefab);
+
+ for (auto _ : state)
+ {
+ state.PauseTiming();
+ m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
+ state.ResumeTiming();
+
+ for (uint64_t spwanableCounter = 0; spwanableCounter < spawnAllEntitiesCallCount; spwanableCounter++)
+ {
+ AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
+ }
+
+ m_rootSpawnableInterface->ProcessSpawnableQueue();
+
+ // Destroy the ticket so that this queues a request to delete all the entities spawned with this ticket.
+ state.PauseTiming();
+ delete m_spawnTicket;
+ m_spawnTicket = nullptr;
+
+ // This will process the request to delete all entities spawned with the ticket
+ m_rootSpawnableInterface->ProcessSpawnableQueue();
+ state.ResumeTiming();
+ }
+
+ state.SetComplexityN(spawnAllEntitiesCallCount);
+ }
+ BENCHMARK_REGISTER_F(BM_SpawnAllEntities, SingleEntitySpawnable_SpawnCallVariable)
+ ->RangeMultiplier(10)
+ ->Range(100, 10000)
+ ->Unit(benchmark::kMillisecond)
+ ->Complexity();
+
+ BENCHMARK_DEFINE_F(BM_SpawnAllEntities, SingleSpawnCall_EntityCountVariable)(::benchmark::State& state)
+ {
+ const uint64_t entityCountInSpawnable = aznumeric_cast(state.range());
+
+ SetUpSpawnableAsset(entityCountInSpawnable);
+
+ for (auto _ : state)
+ {
+ state.PauseTiming();
+ m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
+ state.ResumeTiming();
+
+ AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
+ m_rootSpawnableInterface->ProcessSpawnableQueue();
+
+ // Destroy the ticket so that this queues a request to delete all the entities spawned with this ticket.
+ state.PauseTiming();
+ delete m_spawnTicket;
+ m_spawnTicket = nullptr;
+
+ // This will process the request to delete all entities spawned with the ticket
+ m_rootSpawnableInterface->ProcessSpawnableQueue();
+ state.ResumeTiming();
+ }
+
+ state.SetComplexityN(entityCountInSpawnable);
+ }
+ BENCHMARK_REGISTER_F(BM_SpawnAllEntities, SingleSpawnCall_EntityCountVariable)
+ ->RangeMultiplier(10)
+ ->Range(100, 10000)
+ ->Unit(benchmark::kMillisecond)
+ ->Complexity();
+
+ BENCHMARK_DEFINE_F(BM_SpawnAllEntities, EntityCountVariable_SpawnCallCountVariable)(::benchmark::State& state)
+ {
+ const uint64_t entityCountInSpawnable = aznumeric_cast(state.range(0));
+ const uint64_t spawnCallCount = aznumeric_cast(state.range(1));
+
+ SetUpSpawnableAsset(entityCountInSpawnable);
+
+ for (auto _ : state)
+ {
+ state.PauseTiming();
+ m_spawnTicket = new AzFramework::EntitySpawnTicket(m_spawnableAsset);
+ state.ResumeTiming();
+
+ for (uint64_t spawnCallCounter = 0; spawnCallCounter < spawnCallCount; spawnCallCounter++)
+ {
+ AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*m_spawnTicket);
+ }
+
+ m_rootSpawnableInterface->ProcessSpawnableQueue();
+
+ state.PauseTiming();
+ delete m_spawnTicket;
+ m_spawnTicket = nullptr;
+ m_rootSpawnableInterface->ProcessSpawnableQueue();
+ state.ResumeTiming();
+ }
+
+ state.SetComplexityN(entityCountInSpawnable * spawnCallCount);
+ }
+ // Provide ranges here to compare times for spawning the same number of entities by altering entityCountInSpawnable and spawnCallCount.
+ BENCHMARK_REGISTER_F(BM_SpawnAllEntities, EntityCountVariable_SpawnCallCountVariable)
+ ->Args({ 10, 100 })
+ ->Args({ 100, 10 })
+ ->Args({ 10, 1000 })
+ ->Args({ 1000, 10 })
+ ->Args({ 100, 1000 })
+ ->Args({ 1000, 100 })
+ ->Unit(benchmark::kMillisecond)
+ ->Complexity();
+} // namespace Benchmark
+
+#endif
diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp
new file mode 100644
index 0000000000..fc90d96422
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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
+ *
+ */
+#if defined(HAVE_BENCHMARK)
+
+#include
+#include
+
+namespace Benchmark
+{
+ void BM_Spawnable::SetUp(const benchmark::State& state)
+ {
+ SetUpHelper(state);
+ }
+
+ void BM_Spawnable::SetUp(benchmark::State& state)
+ {
+ SetUpHelper(state);
+ }
+
+ void BM_Spawnable::SetUpHelper(const benchmark::State& state)
+ {
+ BM_Prefab::SetUp(state);
+ m_rootSpawnableInterface = AzFramework::RootSpawnableInterface::Get();
+ AZ_Assert(m_rootSpawnableInterface != nullptr, "RootSpawnableInterface isn't found.");
+ }
+
+ void BM_Spawnable::TearDown(const benchmark::State& state)
+ {
+ TearDownHelper(state);
+ }
+
+ void BM_Spawnable::TearDown(benchmark::State& state)
+ {
+ TearDownHelper(state);
+ }
+
+ void BM_Spawnable::TearDownHelper(const benchmark::State& state)
+ {
+ m_spawnableAsset.Release();
+ BM_Prefab::TearDown(state);
+ }
+
+ void BM_Spawnable::SetUpSpawnableAsset(uint64_t entityCount)
+ {
+ AZStd::vector entities;
+ entities.reserve(entityCount);
+
+ for (uint64_t i = 0; i < entityCount; i++)
+ {
+ entities.emplace_back(CreateEntity("Entity"));
+ }
+
+ AZStd::unique_ptr instance = m_prefabSystemComponent->CreatePrefab(AZStd::move(entities), {}, m_pathString);
+ const PrefabDom& prefabDom = m_prefabSystemComponent->FindTemplateDom(instance->GetTemplateId());
+
+ // Lifecycle of spawnable is managed by the asset that's created using it.
+ AzFramework::Spawnable* spawnable = new AzFramework::Spawnable(
+ AZ::Data::AssetId::CreateString("{612F2AB1-30DF-44BB-AFBE-17A85199F09E}:0"), AZ::Data::AssetData::AssetStatus::Ready);
+ AzToolsFramework::Prefab::SpawnableUtils::CreateSpawnable(*spawnable, prefabDom);
+ m_spawnableAsset = AZ::Data::Asset(spawnable, AZ::Data::AssetLoadBehavior::Default);
+ }
+} // namespace Benchmark
+
+#endif
diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h
new file mode 100644
index 0000000000..6c7fbf6263
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h
@@ -0,0 +1,44 @@
+/*
+ * 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
+ *
+ */
+
+#if defined(HAVE_BENCHMARK)
+
+#pragma once
+
+#include
+#include
+
+namespace AzFramework
+{
+ class EntitySpawnTicket;
+ class RootSpawnableDefinition;
+}
+
+namespace Benchmark
+{
+ class BM_Spawnable
+ : public Benchmark::BM_Prefab
+ {
+ protected:
+ void SetUp(const benchmark::State& state) override;
+ void SetUp(benchmark::State& state) override;
+ void SetUpHelper(const benchmark::State& state);
+
+ void TearDown(const benchmark::State& state) override;
+ void TearDown(benchmark::State& state) override;
+ void TearDownHelper(const benchmark::State& state);
+
+ void SetUpSpawnableAsset(uint64_t entityCount);
+
+ AZ::Data::Asset m_spawnableAsset;
+ AzFramework::EntitySpawnTicket* m_spawnTicket;
+ AzFramework::RootSpawnableDefinition* m_rootSpawnableInterface;
+ };
+} // namespace Benchmark
+
+#endif
diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
index 008c09188b..e3742041b4 100644
--- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
+++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
@@ -60,6 +60,9 @@ set(FILES
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
+ Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h
+ Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp
+ Prefab/Benchmark/Spawnable/SpawnAllEntitiesBenchmarks.cpp
Prefab/PrefabFocus/PrefabFocusTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h
diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp
index 0ef9cdfc3b..0f832ff1a5 100644
--- a/Code/LauncherUnified/Launcher.cpp
+++ b/Code/LauncherUnified/Launcher.cpp
@@ -9,6 +9,7 @@
#include
#include
+#include
#include
#include
#include
@@ -664,6 +665,8 @@ namespace O3DELauncher
systemInitParams.pSystem = CreateSystemInterface(systemInitParams);
#endif // !defined(AZ_MONOLITHIC_BUILD)
+ AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "LegacySystemInterfaceCreated", R"({})");
+
ReturnCode status = ReturnCode::Success;
if (systemInitParams.pSystem)
diff --git a/Code/Legacy/CryCommon/ISystem.h b/Code/Legacy/CryCommon/ISystem.h
index 948977d02a..103e7b50c2 100644
--- a/Code/Legacy/CryCommon/ISystem.h
+++ b/Code/Legacy/CryCommon/ISystem.h
@@ -739,24 +739,6 @@ public:
#undef GetUserName
#endif
-
-struct IProfilingSystem
-{
- //
- virtual ~IProfilingSystem() {}
- //////////////////////////////////////////////////////////////////////////
- // VTune Profiling interface.
-
- // Summary:
- // Resumes vtune data collection.
- virtual void VTuneResume() = 0;
- // Summary:
- // Pauses vtune data collection.
- virtual void VTunePause() = 0;
- //////////////////////////////////////////////////////////////////////////
- //
-};
-
////////////////////////////////////////////////////////////////////////////////////////////////
// Description:
@@ -851,7 +833,6 @@ struct ISystem
virtual IMovieSystem* GetIMovieSystem() = 0;
virtual ::IConsole* GetIConsole() = 0;
virtual IRemoteConsole* GetIRemoteConsole() = 0;
- virtual IProfilingSystem* GetIProfilingSystem() = 0;
virtual ISystemEventDispatcher* GetISystemEventDispatcher() = 0;
virtual ITimer* GetITimer() = 0;
@@ -1121,8 +1102,8 @@ inline ISystem* GetISystem()
// Description:
// This function must be called once by each module at the beginning, to setup global pointers.
-extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, const char* moduleName);
-extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem(ISystem* pSystem);
+void ModuleInitISystem(ISystem* pSystem, const char* moduleName);
+void ModuleShutdownISystem(ISystem* pSystem);
extern "C" AZ_DLL_EXPORT void InjectEnvironment(void* env);
extern "C" AZ_DLL_EXPORT void DetachEnvironment();
diff --git a/Code/Legacy/CryCommon/Mocks/ISystemMock.h b/Code/Legacy/CryCommon/Mocks/ISystemMock.h
index 9d41b9e77d..a11b60fe68 100644
--- a/Code/Legacy/CryCommon/Mocks/ISystemMock.h
+++ b/Code/Legacy/CryCommon/Mocks/ISystemMock.h
@@ -76,8 +76,6 @@ public:
::IConsole * ());
MOCK_METHOD0(GetIRemoteConsole,
IRemoteConsole * ());
- MOCK_METHOD0(GetIProfilingSystem,
- IProfilingSystem * ());
MOCK_METHOD0(GetISystemEventDispatcher,
ISystemEventDispatcher * ());
MOCK_METHOD0(GetITimer,
diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp
index a68a5150db..845a1101a4 100644
--- a/Code/Legacy/CryCommon/platform_impl.cpp
+++ b/Code/Legacy/CryCommon/platform_impl.cpp
@@ -74,7 +74,7 @@ void InitCRTHandlers() {}
//////////////////////////////////////////////////////////////////////////
// This is an entry to DLL initialization function that must be called for each loaded module
//////////////////////////////////////////////////////////////////////////
-extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName)
+void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName)
{
if (gEnv) // Already registered.
{
@@ -96,7 +96,7 @@ extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused
} // if pSystem
}
-extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem)
+void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem)
{
// Unregister with AZ environment.
AZ::Environment::Detach();
diff --git a/Code/Legacy/CrySystem/AZCoreLogSink.h b/Code/Legacy/CrySystem/AZCoreLogSink.h
index 8c88752e9a..1b09c3198d 100644
--- a/Code/Legacy/CrySystem/AZCoreLogSink.h
+++ b/Code/Legacy/CrySystem/AZCoreLogSink.h
@@ -16,7 +16,7 @@
#include
-namespace AZ
+namespace AZ::Debug
{
AZ_CVAR_EXTERNED(int, bg_traceLogLevel);
}
@@ -64,7 +64,7 @@ public:
if(!hasSetCVar && ready)
{
// AZ logging only has a concept of 3 levels (error, warning, info) but cry logging has 4 levels (..., messaging). If info level is set, we'll turn on messaging as well
- int logLevel = AZ::bg_traceLogLevel == AZ::Debug::LogLevel::Info ? 4 : AZ::bg_traceLogLevel;
+ int logLevel = AZ::Debug::bg_traceLogLevel == AZ::Debug::LogLevel::Info ? 4 : AZ::Debug::bg_traceLogLevel;
gEnv->pConsole->GetCVar("log_WriteToFileVerbosity")->Set(logLevel);
hasSetCVar = true;
diff --git a/Code/Legacy/CrySystem/CrySystem_precompiled.h b/Code/Legacy/CrySystem/CrySystem_precompiled.h
index faa924931f..3ececa6514 100644
--- a/Code/Legacy/CrySystem/CrySystem_precompiled.h
+++ b/Code/Legacy/CrySystem/CrySystem_precompiled.h
@@ -60,13 +60,6 @@
#include
-#if defined(WIN32) || defined(WIN64) || defined(APPLE) || defined(LINUX)
-#if defined(DEDICATED_SERVER)
-// enable/disable map load slicing functionality from the build
-#define MAP_LOADING_SLICING
-#endif
-#endif
-
#ifdef WIN32
#include
#include
diff --git a/Code/Legacy/CrySystem/System.cpp b/Code/Legacy/CrySystem/System.cpp
index 2e18e13841..eebe626918 100644
--- a/Code/Legacy/CrySystem/System.cpp
+++ b/Code/Legacy/CrySystem/System.cpp
@@ -143,9 +143,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include
-// To enable profiling with vtune (https://software.intel.com/en-us/intel-vtune-amplifier-xe), make sure the line below is not commented out
-//#define PROFILE_WITH_VTUNE
-
#include
#include
#endif
@@ -154,10 +151,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include
-// profilers api.
-VTuneFunction VTResume = NULL;
-VTuneFunction VTPause = NULL;
-
// Define global cvars.
SSystemCVars g_cvars;
@@ -697,31 +690,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
m_bPaused = false;
}
-#ifdef PROFILE_WITH_VTUNE
- if (m_bInDevMode)
- {
- if (VTPause != NULL && VTResume != NULL)
- {
- static bool bVtunePaused = true;
-
- const AzFramework::InputChannel* inputChannelScrollLock = AzFramework::InputChannelRequests::FindInputChannel(AzFramework::InputDeviceKeyboard::Key::WindowsSystemScrollLock);
- const bool bPaused = (inputChannelScrollLock ? inputChannelScrollLock->IsActive() : false);
-
- {
- if (bVtunePaused && !bPaused)
- {
- GetIProfilingSystem()->VTuneResume();
- }
- if (!bVtunePaused && bPaused)
- {
- GetIProfilingSystem()->VTunePause();
- }
- bVtunePaused = bPaused;
- }
- }
- }
-#endif //PROFILE_WITH_VTUNE
-
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
if (m_bIgnoreUpdates)
{
@@ -1255,30 +1223,6 @@ CPNoise3* CSystem::GetNoiseGen()
return &m_pNoiseGen;
}
-//////////////////////////////////////////////////////////////////////////
-void CProfilingSystem::VTuneResume()
-{
-#ifdef PROFILE_WITH_VTUNE
- if (VTResume)
- {
- CryLogAlways("VTune Resume");
- VTResume();
- }
-#endif
-}
-
-//////////////////////////////////////////////////////////////////////////
-void CProfilingSystem::VTunePause()
-{
-#ifdef PROFILE_WITH_VTUNE
- if (VTPause)
- {
- VTPause();
- CryLogAlways("VTune Pause");
- }
-#endif
-}
-
//////////////////////////////////////////////////////////////////////
void CSystem::OnLanguageCVarChanged(ICVar* language)
{
diff --git a/Code/Legacy/CrySystem/System.h b/Code/Legacy/CrySystem/System.h
index 015b09a69b..74ce1cbbc2 100644
--- a/Code/Legacy/CrySystem/System.h
+++ b/Code/Legacy/CrySystem/System.h
@@ -105,10 +105,6 @@ struct IDataProbe;
#define PHSYICS_OBJECT_ENTITY 0
-using VTuneFunction = void (__cdecl *)(void);
-extern VTuneFunction VTResume;
-extern VTuneFunction VTPause;
-
#define MAX_STREAMING_POOL_INDEX 6
#define MAX_THREAD_POOL_INDEX 6
@@ -139,7 +135,6 @@ struct SSystemCVars
int sys_ai;
int sys_entitysystem;
int sys_trackview;
- int sys_vtune;
float sys_update_profile_time;
int sys_limit_phys_thread_count;
int sys_MaxFPS;
@@ -169,21 +164,6 @@ extern SSystemCVars g_cvars;
class CSystem;
-struct CProfilingSystem
- : public IProfilingSystem
-{
- //////////////////////////////////////////////////////////////////////////
- // VTune Profiling interface.
-
- // Summary:
- // Resumes vtune data collection.
- void VTuneResume() override;
- // Summary:
- // Pauses vtune data collection.
- void VTunePause() override;
- //////////////////////////////////////////////////////////////////////////
-};
-
class AssetSystem;
/*
@@ -262,7 +242,6 @@ public:
IViewSystem* GetIViewSystem() override;
ILevelSystem* GetILevelSystem() override;
ISystemEventDispatcher* GetISystemEventDispatcher() override { return m_pSystemEventDispatcher; }
- IProfilingSystem* GetIProfilingSystem() override { return &m_ProfilingSystem; }
//////////////////////////////////////////////////////////////////////////
// retrieves the perlin noise singleton instance
CPNoise3* GetNoiseGen() override;
@@ -564,8 +543,6 @@ private: // ------------------------------------------------------
ESystemConfigSpec m_nMaxConfigSpec;
ESystemConfigPlatform m_ConfigPlatform;
- CProfilingSystem m_ProfilingSystem;
-
// Pause mode.
bool m_bPaused;
bool m_bNoUpdate;
@@ -588,9 +565,7 @@ public:
const SFileVersion& GetProductVersion() override;
const SFileVersion& GetBuildVersion() override;
- bool InitVTuneProfiler();
-
- void OpenBasicPaks();
+ void OpenPlatformPaks();
void OpenLanguagePak(const char* sLanguage);
void OpenLanguageAudioPak(const char* sLanguage);
void GetLocalizedPath(const char* sLanguage, AZStd::string& sLocalizedPath);
diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp
index ee1c498a9a..7ce9fcd342 100644
--- a/Code/Legacy/CrySystem/SystemInit.cpp
+++ b/Code/Legacy/CrySystem/SystemInit.cpp
@@ -70,9 +70,6 @@
#include "windows.h"
#include
-// To enable profiling with vtune (https://software.intel.com/en-us/intel-vtune-amplifier-xe), make sure the line below is not commented out
-//#define PROFILE_WITH_VTUNE
-
#endif //WIN32
#include
@@ -173,8 +170,6 @@ void CryEngineSignalHandler(int signal)
//////////////////////////////////////////////////////////////////////////
#if defined(WIN32) || defined(LINUX) || defined(APPLE)
-# define DLL_MODULE_INIT_ISYSTEM "ModuleInitISystem"
-# define DLL_MODULE_SHUTDOWN_ISYSTEM "ModuleShutdownISystem"
# define DLL_INITFUNC_RENDERER "PackageRenderConstructor"
# define DLL_INITFUNC_SOUND "CreateSoundSystem"
# define DLL_INITFUNC_FONT "CreateCryFontInterface"
@@ -188,8 +183,6 @@ void CryEngineSignalHandler(int signal)
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
-# define DLL_MODULE_INIT_ISYSTEM (LPCSTR)2
-# define DLL_MODULE_SHUTDOWN_ISYSTEM (LPCSTR)3
# define DLL_INITFUNC_RENDERER (LPCSTR)1
# define DLL_INITFUNC_RENDERER (LPCSTR)1
# define DLL_INITFUNC_SOUND (LPCSTR)1
@@ -445,18 +438,6 @@ AZStd::unique_ptr CSystem::LoadDLL(const char* dllName)
return handle;
}
- //////////////////////////////////////////////////////////////////////////
- // After loading DLL initialize it by calling ModuleInitISystem
- //////////////////////////////////////////////////////////////////////////
- AZStd::string moduleName = PathUtil::GetFileName(dllName);
-
- typedef void*(*PtrFunc_ModuleInitISystem)(ISystem* pSystem, const char* moduleName);
- PtrFunc_ModuleInitISystem pfnModuleInitISystem = handle->GetFunction(DLL_MODULE_INIT_ISYSTEM);
- if (pfnModuleInitISystem)
- {
- pfnModuleInitISystem(this, moduleName.c_str());
- }
-
return handle;
}
@@ -497,13 +478,6 @@ void CSystem::ShutdownModuleLibraries()
#if !defined(AZ_MONOLITHIC_BUILD)
for (auto iterator = m_moduleDLLHandles.begin(); iterator != m_moduleDLLHandles.end(); ++iterator)
{
- typedef void*( * PtrFunc_ModuleShutdownISystem )(ISystem* pSystem);
-
- PtrFunc_ModuleShutdownISystem pfnModuleShutdownISystem = iterator->second->GetFunction(DLL_MODULE_SHUTDOWN_ISYSTEM);
- if (pfnModuleShutdownISystem)
- {
- pfnModuleShutdownISystem(this);
- }
if (iterator->second->IsLoaded())
{
iterator->second->Unload();
@@ -649,7 +623,7 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
auto projectName = AZ::Utils::GetProjectName();
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Name: %s\n", projectName.empty() ? "None specified" : projectName.c_str());
- OpenBasicPaks();
+ OpenPlatformPaks();
// Load game-specific folder.
LoadConfiguration("game.cfg");
@@ -704,33 +678,6 @@ bool CSystem::InitAudioSystem(const SSystemInitParams& initParams)
return result;
}
-//////////////////////////////////////////////////////////////////////////
-bool CSystem::InitVTuneProfiler()
-{
-#ifdef PROFILE_WITH_VTUNE
-
- WIN_HMODULE hModule = LoadDLL("VTuneApi.dll");
- if (!hModule)
- {
- return false;
- }
-
- VTPause = (VTuneFunction) CryGetProcAddress(hModule, "VTPause");
- VTResume = (VTuneFunction) CryGetProcAddress(hModule, "VTResume");
- if (!VTPause || !VTResume)
- {
- AZ_Assert(false, "VTune did not initialize correctly.")
- return false;
- }
- else
- {
- AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "VTune API Initialized");
- }
-#endif //PROFILE_WITH_VTUNE
-
- return true;
-}
-
//////////////////////////////////////////////////////////////////////////
void CSystem::InitLocalization()
{
@@ -786,29 +733,19 @@ void CSystem::InitLocalization()
OpenLanguageAudioPak(language.c_str());
}
-void CSystem::OpenBasicPaks()
+void CSystem::OpenPlatformPaks()
{
- static bool bBasicPaksLoaded = false;
- if (bBasicPaksLoaded)
+ static bool bPlatformPaksLoaded = false;
+ if (bPlatformPaksLoaded)
{
return;
}
- bBasicPaksLoaded = true;
-
- // open pak files
- constexpr AZStd::string_view paksFolder = "@products@/*.pak"; // (@products@ assumed)
- m_env.pCryPak->OpenPacks(paksFolder);
-
- InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( paksFolder.c_str() )");
+ bPlatformPaksLoaded = true;
//////////////////////////////////////////////////////////////////////////
// Open engine packs
//////////////////////////////////////////////////////////////////////////
- const char* const assetsDir = "@products@";
-
- // After game paks to have same search order as with files on disk
- m_env.pCryPak->OpenPack(assetsDir, "engine.pak");
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_15
@@ -816,6 +753,7 @@ void CSystem::OpenBasicPaks()
#endif
#ifdef AZ_PLATFORM_ANDROID
+ const char* const assetsDir = "@products@";
// Load Android Obb files if available
const char* obbStorage = AZ::Android::Utils::GetObbStoragePath();
AZStd::string mainObbPath = AZStd::move(AZStd::string::format("%s/%s", obbStorage, AZ::Android::Utils::GetObbFileName(true)));
@@ -824,7 +762,7 @@ void CSystem::OpenBasicPaks()
m_env.pCryPak->OpenPack(assetsDir, patchObbPath.c_str());
#endif //AZ_PLATFORM_ANDROID
- InlineInitializationProcessing("CSystem::OpenBasicPaks OpenPacks( Engine... )");
+ InlineInitializationProcessing("CSystem::OpenPlatformPaks OpenPacks( Engine... )");
}
//////////////////////////////////////////////////////////////////////////
@@ -1328,7 +1266,7 @@ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////
// Open basic pak files after intro movie playback started
//////////////////////////////////////////////////////////////////////////
- OpenBasicPaks();
+ OpenPlatformPaks();
//////////////////////////////////////////////////////////////////////////
// AUDIO
@@ -1714,8 +1652,6 @@ void CSystem::CreateSystemVars()
m_sys_memory_debug = REGISTER_INT("sys_memory_debug", 0, VF_CHEAT,
"Enables to activate low memory situation is specific places in the code (argument defines which place), 0=off");
- REGISTER_CVAR2("sys_vtune", &g_cvars.sys_vtune, 0, VF_NULL, "");
-
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_17
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
diff --git a/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp b/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp
index e83676827f..d7e5c081c0 100644
--- a/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp
+++ b/Code/Legacy/CrySystem/ViewSystem/ViewSystem.cpp
@@ -115,17 +115,20 @@ CViewSystem::CViewSystem(ISystem* pSystem)
, m_useDeferredViewSystemUpdate(false)
, m_bControlsAudioListeners(true)
{
-#if !defined(_RELEASE) && !defined(DEDICATED_SERVER)
- if (!s_debugCamera)
+#if !defined(_RELEASE)
+ if (!gEnv->IsDedicated())
{
- s_debugCamera = new DebugCamera;
- }
+ if (!s_debugCamera)
+ {
+ s_debugCamera = new DebugCamera;
+ }
- REGISTER_COMMAND("debugCameraToggle", ToggleDebugCamera, VF_DEV_ONLY, "Toggle the debug camera.\n");
- REGISTER_COMMAND("debugCameraInvertY", ToggleDebugCameraInvertY, VF_DEV_ONLY, "Toggle debug camera Y-axis inversion.\n");
- REGISTER_COMMAND("debugCameraMove", DebugCameraMove, VF_DEV_ONLY, "Move the debug camera the specified distance (x y z).\n");
- gEnv->pConsole->CreateKeyBind("ctrl_keyboard_key_punctuation_backslash", "debugCameraToggle");
- gEnv->pConsole->CreateKeyBind("alt_keyboard_key_punctuation_backslash", "debugCameraInvertY");
+ REGISTER_COMMAND("debugCameraToggle", ToggleDebugCamera, VF_DEV_ONLY, "Toggle the debug camera.\n");
+ REGISTER_COMMAND("debugCameraInvertY", ToggleDebugCameraInvertY, VF_DEV_ONLY, "Toggle debug camera Y-axis inversion.\n");
+ REGISTER_COMMAND("debugCameraMove", DebugCameraMove, VF_DEV_ONLY, "Move the debug camera the specified distance (x y z).\n");
+ gEnv->pConsole->CreateKeyBind("ctrl_keyboard_key_punctuation_backslash", "debugCameraToggle");
+ gEnv->pConsole->CreateKeyBind("alt_keyboard_key_punctuation_backslash", "debugCameraInvertY");
+ }
#endif
REGISTER_CVAR2("cl_camera_noise", &m_fCameraNoise, -1, 0,
@@ -167,6 +170,21 @@ CViewSystem::~CViewSystem()
{
m_pSystem->GetILevelSystem()->RemoveListener(this);
}
+
+#if !defined(_RELEASE)
+ if (!gEnv->IsDedicated())
+ {
+ UNREGISTER_COMMAND("debugCameraToggle");
+ UNREGISTER_COMMAND("debugCameraInvertY");
+ UNREGISTER_COMMAND("debugCameraMove");
+
+ if (s_debugCamera)
+ {
+ delete s_debugCamera;
+ s_debugCamera = nullptr;
+ }
+ }
+#endif
}
//------------------------------------------------------------------------
diff --git a/Code/Tools/AssetBundler/CMakeLists.txt b/Code/Tools/AssetBundler/CMakeLists.txt
index d613b35ce5..dcc62595c9 100644
--- a/Code/Tools/AssetBundler/CMakeLists.txt
+++ b/Code/Tools/AssetBundler/CMakeLists.txt
@@ -47,6 +47,10 @@ ly_add_target(
AZ::AssetBundlerBatch.Static
)
+# Adds a specialized .setreg to identify gems enabled in the active project.
+# This associates the AssetBundlerBatch target with the .Builders gem variants.
+ly_set_gem_variant_to_load(TARGETS AssetBundlerBatch VARIANTS Builders)
+
# AssetBundler - Qt GUI Application
ly_add_target(
NAME AssetBundler ${PAL_TRAIT_BUILD_ASSETBUNDLER_APPLICATION_TYPE}
@@ -73,6 +77,10 @@ ly_add_target(
${additional_dependencies}
)
+# Adds a specialized .setreg to identify gems enabled in the active project.
+# This associates the AssetBundler target with the .Builders gem variants.
+ly_set_gem_variant_to_load(TARGETS AssetBundler VARIANTS Builders)
+
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
diff --git a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp
index 0742035c1a..0388570fdd 100644
--- a/Code/Tools/AssetBundler/source/utils/applicationManager.cpp
+++ b/Code/Tools/AssetBundler/source/utils/applicationManager.cpp
@@ -54,7 +54,12 @@ namespace AssetBundler
bool ApplicationManager::Init()
{
AZ::Debug::TraceMessageBus::Handler::BusConnect();
- Start(AzFramework::Application::Descriptor());
+
+ ComponentApplication::StartupParameters startupParameters;
+ // The AssetBundler does not need to load gems
+ startupParameters.m_loadDynamicModules = false;
+ Start(AzFramework::Application::Descriptor(), startupParameters);
+
AZ::SerializeContext* context;
EBUS_EVENT_RESULT(context, AZ::ComponentApplicationBus, GetSerializeContext);
AZ_Assert(context, "No serialize context");
diff --git a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp
index 35d3a5da1f..0d915dcc49 100644
--- a/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp
+++ b/Code/Tools/AssetBundler/tests/applicationManagerTests.cpp
@@ -71,7 +71,11 @@ namespace AssetBundler
m_data->m_applicationManager.reset(aznew MockApplicationManagerTest(0, 0));
- m_data->m_applicationManager->Start(AzFramework::Application::Descriptor());
+
+ AZ::ComponentApplication::StartupParameters startupParameters;
+ // The AssetBundler does not need to load gems
+ startupParameters.m_loadDynamicModules = false;
+ m_data->m_applicationManager->Start(AzFramework::Application::Descriptor(), startupParameters);
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
diff --git a/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp b/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp
index 9be991eb0b..8f7d542fcc 100644
--- a/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp
+++ b/Code/Tools/AssetProcessor/native/AssetDatabase/AssetDatabase.cpp
@@ -1067,12 +1067,15 @@ namespace AssetProcessor
if (dropAllTables)
{
+ AZ_TracePrintf("AssetDatabase", "Closing existing db connection\n"); // Temporary debug output to help with tracking down a crash
// drop all tables by destroying the entire database.
m_databaseConnection->Close();
+ AZ_TracePrintf("AssetDatabase", "Getting db file path\n"); // Temporary debug output to help with tracking down a crash
AZStd::string dbFilePath = GetAssetDatabaseFilePath();
if (dbFilePath != ":memory:")
{
+ AZ_TracePrintf("AssetDatabase", "Deleting existing db %s\n", dbFilePath.c_str()); // Temporary debug output to help with tracking down a crash
// you cannot delete a memory database, but it drops all data when you close it anyway.
if (!AZ::IO::SystemFile::Delete(dbFilePath.c_str()))
{
@@ -1082,7 +1085,7 @@ namespace AssetProcessor
return false;
}
}
-
+ AZ_TracePrintf("AssetDatabase", "Re-opening connection\n"); // Temporary debug output to help with tracking down a crash
if (!m_databaseConnection->Open(dbFilePath, IsReadOnly()))
{
delete m_databaseConnection;
diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp
index 5e061491f0..367a296bd4 100644
--- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp
+++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp
@@ -4027,30 +4027,43 @@ namespace AssetProcessor
// It is generally called when a source file modified in any way, including when it is added or deleted.
// note that this is a "reverse" dependency query - it looks up what depends on a file, not what the file depends on
using namespace AzToolsFramework::AssetDatabase;
- QStringList absoluteSourceFilePathQueue;
+ QSet absoluteSourceFilePathQueue;
QString databasePath;
QString scanFolder;
- auto callbackFunction = [&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& entry)
+ auto callbackFunction = [this, &absoluteSourceFilePathQueue](SourceFileDependencyEntry& entry)
{
QString relativeDatabaseName = QString::fromUtf8(entry.m_source.c_str());
QString absolutePath = m_platformConfig->FindFirstMatchingFile(relativeDatabaseName);
if (!absolutePath.isEmpty())
{
- absoluteSourceFilePathQueue.push_back(absolutePath);
+ absoluteSourceFilePathQueue.insert(absolutePath);
}
return true;
};
+ auto callbackFunctionAbsoluteCheck = [&callbackFunction](SourceFileDependencyEntry& entry)
+ {
+ if (AZ::IO::PathView(entry.m_dependsOnSource.c_str()).IsAbsolute())
+ {
+ return callbackFunction(entry);
+ }
+
+ return true;
+ };
+
// convert to a database path so that the standard function can be called.
if (m_platformConfig->ConvertToRelativePath(sourcePath, databasePath, scanFolder))
{
m_stateData->QuerySourceDependencyByDependsOnSource(databasePath.toUtf8().constData(), nullptr, SourceFileDependencyEntry::DEP_Any, callbackFunction);
-
}
- return absoluteSourceFilePathQueue;
+ // We'll also check with the absolute path, because we support absolute path dependencies
+ m_stateData->QuerySourceDependencyByDependsOnSource(
+ sourcePath.toUtf8().constData(), nullptr, SourceFileDependencyEntry::DEP_Any, callbackFunctionAbsoluteCheck);
+
+ return absoluteSourceFilePathQueue.values();
}
void AssetProcessorManager::AddSourceToDatabase(AzToolsFramework::AssetDatabase::SourceDatabaseEntry& sourceDatabaseEntry, const ScanFolderInfo* scanFolder, QString relativeSourceFilePath)
diff --git a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
index c65ab24aed..7823a0582f 100644
--- a/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
+++ b/Code/Tools/AssetProcessor/native/InternalBuilders/SettingsRegistryBuilder.cpp
@@ -159,6 +159,7 @@ namespace AssetProcessor
builderDesc.m_busId = m_builderId;
builderDesc.m_createJobFunction = AZStd::bind(&SettingsRegistryBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDesc.m_processJobFunction = AZStd::bind(&SettingsRegistryBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2);
+ builderDesc.m_version = 1;
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDesc);
@@ -259,6 +260,11 @@ namespace AssetProcessor
scratchBuffer.reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
AZStd::fixed_vector platformCodes;
AzFramework::PlatformHelper::AppendPlatformCodeNames(platformCodes, request.m_platformInfo.m_identifier);
+ AZ_Assert(platformCodes.size() <= 1, "A one-to-one mapping of asset type platform identifier"
+ " to platform codename is required in the SettingsRegistryBuilder."
+ " The bootstrap.game is now only produced per build configuration and doesn't take into account"
+ " different platforms names");
+
const AZStd::string& assetPlatformIdentifier = request.m_jobDescription.GetPlatformIdentifier();
// Determines the suffix that will be used for the launcher based on processing server vs non-server assets
const char* launcherType = assetPlatformIdentifier != AzFramework::PlatformHelper::GetPlatformName(AzFramework::PlatformId::SERVER)
@@ -293,9 +299,9 @@ namespace AssetProcessor
outputBuffer.Reserve(512 * 1024); // Reserve 512kb to avoid repeatedly resizing the buffer;
SettingsExporter exporter(outputBuffer, excludes);
- for (AZStd::string_view platform : platformCodes)
+ if (!platformCodes.empty())
{
- AZ::u32 productSubID = static_cast(AZStd::hash{}(platform)); // Deliberately ignoring half the bits.
+ AZStd::string_view platform = platformCodes.front();
for (size_t i = 0; i < AZStd::size(specializations); ++i)
{
const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i];
@@ -337,7 +343,7 @@ namespace AssetProcessor
// The purpose of this section is to copy the Gem's SourcePaths from the Global Settings Registry
// the local SettingsRegistry. The reason this is needed is so that the call to
// `MergeSettingsToRegistry_GemRegistries` below is able to locate each gem's "/Registry" folder
- // that will be merged into the bootstrap.game...setreg file
+ // that will be merged into the bootstrap.game..setreg file
// This is used by the GameLauncher applications to read from a single merged .setreg file
// containing the settings needed to run a game/simulation without have access to the source code base registry
AZStd::vector gemInfos;
@@ -407,9 +413,8 @@ namespace AssetProcessor
return;
}
- outputPath += specialization.GetSpecialization(0); // Append configuration
- outputPath += '.';
- outputPath += platform;
+ AZStd::string_view specializationString(specialization.GetSpecialization(0));
+ outputPath += specializationString; // Append configuration
outputPath += ".setreg";
AZ::IO::SystemFile file;
@@ -426,7 +431,10 @@ namespace AssetProcessor
}
file.Close();
- response.m_outputProducts.emplace_back(outputPath, m_assetType, productSubID + aznumeric_cast(i));
+ AZ::u32 hashedSpecialization = static_cast(AZStd::hash{}(specializationString));
+ AZ_Assert(hashedSpecialization != 0, "Product ID generation failed for specialization %.*s. This can result in a product ID collision with other builders for this asset.",
+ AZ_STRING_ARG(specializationString));
+ response.m_outputProducts.emplace_back(outputPath, m_assetType, hashedSpecialization);
response.m_outputProducts.back().m_dependenciesHandled = true;
outputPath.erase(extensionOffset);
diff --git a/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h b/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h
index 258268c182..df40683027 100644
--- a/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h
+++ b/Code/Tools/AssetProcessor/native/tests/AssetProcessorTest.h
@@ -25,7 +25,7 @@ namespace AssetProcessor
: public ::testing::Test
{
protected:
- UnitTestUtils::AssertAbsorber* m_errorAbsorber;
+ AZStd::unique_ptr m_errorAbsorber{};
FileStatePassthrough m_fileStateCache;
void SetUp() override
@@ -40,7 +40,7 @@ namespace AssetProcessor
m_ownsSysAllocator = true;
AZ::AllocatorInstance::Create();
}
- m_errorAbsorber = new UnitTestUtils::AssertAbsorber();
+ m_errorAbsorber = AZStd::make_unique();
m_application = AZStd::make_unique();
@@ -60,8 +60,8 @@ namespace AssetProcessor
AssetUtilities::ResetAssetRoot();
m_application.reset();
- delete m_errorAbsorber;
- m_errorAbsorber = nullptr;
+ m_errorAbsorber.reset();
+
if (m_ownsSysAllocator)
{
AZ::AllocatorInstance::Destroy();
diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
index 6c19213414..0cbdc20f1c 100644
--- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
+++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
@@ -241,8 +241,10 @@ void AssetProcessorManagerTest::SetUp()
ASSERT_TRUE(m_mockApplicationManager->RegisterAssetRecognizerAsBuilder(rec));
m_mockApplicationManager->BusConnect();
+ AZ_Printf("UnitTest", "Allocating APM\n")
m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get()));
- m_assertAbsorber.Clear();
+ AZ_Printf("UnitTest", "APM ready\n");
+ m_errorAbsorber->Clear();
m_isIdling = false;
@@ -333,9 +335,9 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess)
EXPECT_STRCASEEQ(relFileName.toUtf8().data(), response.m_jobList[0].m_sourceFile.c_str());
EXPECT_STRCASEEQ(tempPath.filePath("subfolder1").toUtf8().data(), response.m_jobList[0].m_watchFolder.c_str());
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase)
@@ -387,9 +389,9 @@ TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToD
ASSERT_EQ(response.m_jobList[0].m_warningCount, 11);
ASSERT_EQ(response.m_jobList[0].m_errorCount, 22);
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
@@ -1311,8 +1313,8 @@ void PathDependencyTest::SetUp()
void PathDependencyTest::TearDown()
{
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
AssetProcessorManagerTest::TearDown();
}
@@ -1616,7 +1618,7 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
mainFile.m_products.push_back(productAssetId);
// tell the APM that the asset has been processed and allow it to bubble through its event queue:
- m_assertAbsorber.Clear();
+ m_errorAbsorber->Clear();
m_assetProcessorManager->AssetProcessed(jobDetails.m_jobEntry, processJobResponse);
ASSERT_TRUE(BlockUntilIdle(5000));
@@ -1626,8 +1628,8 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
ASSERT_TRUE(dependencyContainer.empty());
// We are testing 2 different dependencies, so we should get 2 warnings
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 2);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 2);
+ m_errorAbsorber->Clear();
}
// This test shows the process of deferring resolution of a path dependency works.
@@ -1944,8 +1946,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludePathsExisting_ResolveCorr
);
// Test asset PrimaryFile1 has 4 conflict dependencies
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 4);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 4);
+ m_errorAbsorber->Clear();
}
TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly)
@@ -2092,8 +2094,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludedPathDeferred_ResolveCorr
// Test asset PrimaryFile1 has 4 conflict dependencies
// After test assets dep2 and dep3 are processed,
// another 2 errors will be raised because of the confliction
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 6);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 6);
+ m_errorAbsorber->Clear();
}
void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst)
@@ -4138,11 +4140,19 @@ struct LockedFileTest
switch (message.GetMessageType())
{
case SourceFileNotificationMessage::MessageType:
- if (const auto sourceFileMessage = azrtti_cast(&message);
- sourceFileMessage != nullptr && sourceFileMessage->m_type == SourceFileNotificationMessage::NotificationType::FileRemoved
- && m_callback)
+ if (const auto sourceFileMessage = azrtti_cast(&message); sourceFileMessage != nullptr &&
+ sourceFileMessage->m_type == SourceFileNotificationMessage::NotificationType::FileRemoved)
{
- m_callback();
+ // The File Remove message will occur before an attempt to delete the file
+ // Wait for more than 1 File Remove message.
+ // This indicates the AP has attempted to delete the file once, failed to do so and is now retrying
+ ++m_deleteCounter;
+
+ if(m_deleteCounter > 1 && m_callback)
+ {
+ m_callback();
+ m_callback = {}; // Unset it to be safe, we only intend to run the callback once
+ }
}
break;
default:
@@ -4166,6 +4176,7 @@ struct LockedFileTest
ModtimeScanningTest::TearDown();
}
+ AZStd::atomic_int m_deleteCounter{ 0 };
AZStd::function