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/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
index ff3cd5c465..87a66c880e 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
@@ -20,19 +20,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED)
COMPONENT
Atom
)
- ly_add_pytest(
- NAME AutomatedTesting::Atom_TestSuite_Main_Optimized
- TEST_SUITE main
- PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
- TEST_SERIAL
- TIMEOUT 600
- RUNTIME_DEPENDENCIES
- AssetProcessor
- AutomatedTesting.Assets
- Editor
- COMPONENT
- Atom
- )
ly_add_pytest(
NAME AutomatedTesting::Atom_TestSuite_Sandbox
TEST_SUITE sandbox
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
index 6cc48984ab..cce9a27da6 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py
@@ -4,252 +4,91 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
-import logging
-import os
-
import pytest
-import ly_test_tools.environment.file_system as file_system
-import editor_python_test_tools.hydra_test_utils as hydra
-from Atom.atom_utils.atom_constants import LIGHT_TYPES
-
-logger = logging.getLogger(__name__)
-TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
+from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-@pytest.mark.parametrize("level", ["auto_test"])
-class TestAtomEditorComponentsMain(object):
- """Holds tests for Atom components."""
-
- @pytest.mark.test_case_id("C32078118") # Decal
- @pytest.mark.test_case_id("C32078119") # DepthOfField
- @pytest.mark.test_case_id("C32078120") # Directional Light
- @pytest.mark.test_case_id("C32078121") # Exposure Control
- @pytest.mark.test_case_id("C32078115") # Global Skylight (IBL)
- @pytest.mark.test_case_id("C32078125") # Physical Sky
- @pytest.mark.test_case_id("C32078127") # PostFX Layer
- @pytest.mark.test_case_id("C32078131") # PostFX Radius Weight Modifier
- @pytest.mark.test_case_id("C32078117") # Light
- @pytest.mark.test_case_id("C36525660") # Display Mapper
- def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
- """
- Please review the hydra script run by this test for more specific test info.
- Tests the Atom components & verifies all "expected_lines" appear in Editor.log
- """
- cfg_args = [level]
-
- expected_lines = [
- # Decal Component
- "Decal Entity successfully created",
- "Decal_test: Component added to the entity: True",
- "Decal_test: Component removed after UNDO: True",
- "Decal_test: Component added after REDO: True",
- "Decal_test: Entered game mode: True",
- "Decal_test: Exit game mode: True",
- "Decal Controller|Configuration|Material: SUCCESS",
- "Decal_test: Entity is hidden: True",
- "Decal_test: Entity is shown: True",
- "Decal_test: Entity deleted: True",
- "Decal_test: UNDO entity deletion works: True",
- "Decal_test: REDO entity deletion works: True",
- # DepthOfField Component
- "DepthOfField Entity successfully created",
- "DepthOfField_test: Component added to the entity: True",
- "DepthOfField_test: Component removed after UNDO: True",
- "DepthOfField_test: Component added after REDO: True",
- "DepthOfField_test: Entered game mode: True",
- "DepthOfField_test: Exit game mode: True",
- "DepthOfField_test: Entity disabled initially: True",
- "DepthOfField_test: Entity enabled after adding required components: True",
- "DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
- "DepthOfField_test: Entity is hidden: True",
- "DepthOfField_test: Entity is shown: True",
- "DepthOfField_test: Entity deleted: True",
- "DepthOfField_test: UNDO entity deletion works: True",
- "DepthOfField_test: REDO entity deletion works: True",
- # Directional Light Component
- "Directional Light Entity successfully created",
- "Directional Light_test: Component added to the entity: True",
- "Directional Light_test: Component removed after UNDO: True",
- "Directional Light_test: Component added after REDO: True",
- "Directional Light_test: Entered game mode: True",
- "Directional Light_test: Exit game mode: True",
- "Directional Light_test: Entity is hidden: True",
- "Directional Light_test: Entity is shown: True",
- "Directional Light_test: Entity deleted: True",
- "Directional Light_test: UNDO entity deletion works: True",
- "Directional Light_test: REDO entity deletion works: True",
- # Exposure Control Component
- "Exposure Control Entity successfully created",
- "Exposure Control_test: Component added to the entity: True",
- "Exposure Control_test: Component removed after UNDO: True",
- "Exposure Control_test: Component added after REDO: True",
- "Exposure Control_test: Entered game mode: True",
- "Exposure Control_test: Exit game mode: True",
- "Exposure Control_test: Entity disabled initially: True",
- "Exposure Control_test: Entity enabled after adding required components: True",
- "Exposure Control_test: Entity is hidden: True",
- "Exposure Control_test: Entity is shown: True",
- "Exposure Control_test: Entity deleted: True",
- "Exposure Control_test: UNDO entity deletion works: True",
- "Exposure Control_test: REDO entity deletion works: True",
- # Global Skylight (IBL) Component
- "Global Skylight (IBL) Entity successfully created",
- "Global Skylight (IBL)_test: Component added to the entity: True",
- "Global Skylight (IBL)_test: Component removed after UNDO: True",
- "Global Skylight (IBL)_test: Component added after REDO: True",
- "Global Skylight (IBL)_test: Entered game mode: True",
- "Global Skylight (IBL)_test: Exit game mode: True",
- "Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
- "Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
- "Global Skylight (IBL)_test: Entity is hidden: True",
- "Global Skylight (IBL)_test: Entity is shown: True",
- "Global Skylight (IBL)_test: Entity deleted: True",
- "Global Skylight (IBL)_test: UNDO entity deletion works: True",
- "Global Skylight (IBL)_test: REDO entity deletion works: True",
- # Physical Sky Component
- "Physical Sky Entity successfully created",
- "Physical Sky component was added to entity",
- "Entity has a Physical Sky component",
- "Physical Sky_test: Component added to the entity: True",
- "Physical Sky_test: Component removed after UNDO: True",
- "Physical Sky_test: Component added after REDO: True",
- "Physical Sky_test: Entered game mode: True",
- "Physical Sky_test: Exit game mode: True",
- "Physical Sky_test: Entity is hidden: True",
- "Physical Sky_test: Entity is shown: True",
- "Physical Sky_test: Entity deleted: True",
- "Physical Sky_test: UNDO entity deletion works: True",
- "Physical Sky_test: REDO entity deletion works: True",
- # PostFX Layer Component
- "PostFX Layer Entity successfully created",
- "PostFX Layer_test: Component added to the entity: True",
- "PostFX Layer_test: Component removed after UNDO: True",
- "PostFX Layer_test: Component added after REDO: True",
- "PostFX Layer_test: Entered game mode: True",
- "PostFX Layer_test: Exit game mode: True",
- "PostFX Layer_test: Entity is hidden: True",
- "PostFX Layer_test: Entity is shown: True",
- "PostFX Layer_test: Entity deleted: True",
- "PostFX Layer_test: UNDO entity deletion works: True",
- "PostFX Layer_test: REDO entity deletion works: True",
- # PostFX Radius Weight Modifier Component
- "PostFX Radius Weight Modifier Entity successfully created",
- "PostFX Radius Weight Modifier_test: Component added to the entity: True",
- "PostFX Radius Weight Modifier_test: Component removed after UNDO: True",
- "PostFX Radius Weight Modifier_test: Component added after REDO: True",
- "PostFX Radius Weight Modifier_test: Entered game mode: True",
- "PostFX Radius Weight Modifier_test: Exit game mode: True",
- "PostFX Radius Weight Modifier_test: Entity is hidden: True",
- "PostFX Radius Weight Modifier_test: Entity is shown: True",
- "PostFX Radius Weight Modifier_test: Entity deleted: True",
- "PostFX Radius Weight Modifier_test: UNDO entity deletion works: True",
- "PostFX Radius Weight Modifier_test: REDO entity deletion works: True",
- # Light Component
- "Light Entity successfully created",
- "Light_test: Component added to the entity: True",
- "Light_test: Component removed after UNDO: True",
- "Light_test: Component added after REDO: True",
- "Light_test: Entered game mode: True",
- "Light_test: Exit game mode: True",
- "Light_test: Entity is hidden: True",
- "Light_test: Entity is shown: True",
- "Light_test: Entity deleted: True",
- "Light_test: UNDO entity deletion works: True",
- "Light_test: REDO entity deletion works: True",
- # Display Mapper Component
- "Display Mapper Entity successfully created",
- "Display Mapper_test: Component added to the entity: True",
- "Display Mapper_test: Component removed after UNDO: True",
- "Display Mapper_test: Component added after REDO: True",
- "Display Mapper_test: Entered game mode: True",
- "Display Mapper_test: Exit game mode: True",
- "Display Mapper_test: Entity is hidden: True",
- "Display Mapper_test: Entity is shown: True",
- "Display Mapper_test: Entity deleted: True",
- "Display Mapper_test: UNDO entity deletion works: True",
- "Display Mapper_test: REDO entity deletion works: True",
- ]
-
- unexpected_lines = [
- "Trace::Assert",
- "Trace::Error",
- "Traceback (most recent call last):",
- ]
-
- hydra.launch_and_validate_results(
- request,
- TEST_DIRECTORY,
- editor,
- "hydra_AtomEditorComponents_AddedToEntity.py",
- timeout=120,
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- halt_on_unexpected=True,
- null_renderer=True,
- cfg_args=cfg_args,
- )
-
- @pytest.mark.test_case_id("C34525095")
- def test_AtomEditorComponents_LightComponent(
- self, request, editor, workspace, project, launcher_platform, level):
- """
- Please review the hydra script run by this test for more specific test info.
- Tests that the Light component has the expected property options available to it.
- """
- cfg_args = [level]
-
- expected_lines = [
- "light_entity Entity successfully created",
- "Entity has a Light component",
- "light_entity_test: Component added to the entity: True",
- f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
- "Controller|Configuration|Shadows|Enable shadow set to True",
- "light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
- "Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
- "Controller|Configuration|Shadows|Filtering sample count set to 4",
- "Controller|Configuration|Shadows|Filtering sample count set to 64",
- "Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
- "Controller|Configuration|Shadows|ESM exponent set to 50.0",
- "Controller|Configuration|Shadows|ESM exponent set to 5000.0",
- "Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
- f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
- f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
- f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
- "light_entity Controller|Configuration|Fast approximation: SUCCESS",
- "light_entity Controller|Configuration|Both directions: SUCCESS",
- f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
- f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
- f"which matches {LIGHT_TYPES['simple_point']}",
- "Controller|Configuration|Attenuation radius|Mode set to 0",
- "Controller|Configuration|Attenuation radius|Radius set to 100.0",
- f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
- f"which matches {LIGHT_TYPES['simple_spot']}",
- "Controller|Configuration|Shutters|Outer angle set to 45.0",
- "Controller|Configuration|Shutters|Outer angle set to 90.0",
- "light_entity_test: Component added to the entity: True",
- "Light component test (non-GPU) completed.",
- ]
-
- unexpected_lines = [
- "Trace::Assert",
- "Trace::Error",
- "Traceback (most recent call last):",
- ]
-
- hydra.launch_and_validate_results(
- request,
- TEST_DIRECTORY,
- editor,
- "hydra_AtomEditorComponents_LightComponent.py",
- timeout=120,
- expected_lines=expected_lines,
- unexpected_lines=unexpected_lines,
- halt_on_unexpected=True,
- null_renderer=True,
- cfg_args=cfg_args,
- )
-
-
+class TestAutomation(EditorTestSuite):
+
+ @pytest.mark.test_case_id("C36525657")
+ class AtomEditorComponents_BloomAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_BloomAdded as test_module
+
+ @pytest.mark.test_case_id("C32078118")
+ class AtomEditorComponents_DecalAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
+
+ @pytest.mark.test_case_id("C32078119")
+ class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
+
+ @pytest.mark.test_case_id("C32078120")
+ class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
+
+ @pytest.mark.test_case_id("C36525660")
+ class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
+
+ @pytest.mark.test_case_id("C32078121")
+ class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
+
+ @pytest.mark.test_case_id("C32078115")
+ class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
+
+ @pytest.mark.test_case_id("C32078122")
+ 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
+
+ @pytest.mark.test_case_id("C32078123")
+ class AtomEditorComponents_MaterialAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module
+
+ @pytest.mark.test_case_id("C32078124")
+ 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
+
+ @pytest.mark.test_case_id("C36525664")
+ class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module
+
+ @pytest.mark.test_case_id("C32078127")
+ class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module
+
+ @pytest.mark.test_case_id("C32078131")
+ class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
+ from Atom.tests import (
+ hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
+
+ @pytest.mark.test_case_id("C36525665")
+ class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module
+
+ @pytest.mark.test_case_id("C32078128")
+ class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
+ from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
+
+ class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
+ from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
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
deleted file mode 100644
index 45298ed563..0000000000
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py
+++ /dev/null
@@ -1,83 +0,0 @@
-"""
-Copyright (c) Contributors to the Open 3D Engine Project.
-For complete copyright and license terms please see the LICENSE at the root of this distribution.
-
-SPDX-License-Identifier: Apache-2.0 OR MIT
-"""
-import pytest
-
-from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
-
-
-@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
-@pytest.mark.parametrize("project", ["AutomatedTesting"])
-@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
-class TestAutomation(EditorTestSuite):
-
- @pytest.mark.test_case_id("C32078118")
- class AtomEditorComponents_DecalAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
-
- @pytest.mark.test_case_id("C32078119")
- class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
-
- @pytest.mark.test_case_id("C32078120")
- class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
-
- @pytest.mark.test_case_id("C36525660")
- class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
-
- @pytest.mark.test_case_id("C32078121")
- class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
-
- @pytest.mark.test_case_id("C32078115")
- class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
-
- @pytest.mark.test_case_id("C32078122")
- class AtomEditorComponents_GridAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module
-
- @pytest.mark.test_case_id("C32078117")
- class AtomEditorComponents_LightAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
-
- @pytest.mark.test_case_id("C32078123")
- class AtomEditorComponents_MaterialAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module
-
- @pytest.mark.test_case_id("C32078124")
- class AtomEditorComponents_MeshAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
-
- @pytest.mark.test_case_id("C32078125")
- class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
-
- @pytest.mark.test_case_id("C36525664")
- class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module
-
- @pytest.mark.test_case_id("C32078127")
- class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module
-
- @pytest.mark.test_case_id("C32078131")
- class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
- from Atom.tests import (
- hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
-
- @pytest.mark.test_case_id("C36525665")
- class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module
-
- @pytest.mark.test_case_id("C32078128")
- class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
- from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
-
- class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
- from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
index ad45e51080..9ceb3c951f 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py
@@ -9,63 +9,84 @@ import os
import pytest
+import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
+from Atom.atom_utils.atom_constants import LIGHT_TYPES
+
logger = logging.getLogger(__name__)
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
+
class TestAtomEditorComponentsSandbox(object):
# It requires at least one test
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
pass
- @pytest.mark.parametrize("project", ["AutomatedTesting"])
- @pytest.mark.parametrize("launcher_platform", ['windows_editor'])
- @pytest.mark.parametrize("level", ["auto_test"])
- class TestAtomEditorComponentsMain(object):
- """Holds tests for Atom components."""
-
- @pytest.mark.test_case_id("C32078128")
- def test_AtomEditorComponents_ReflectionProbeAddedToEntity(
- self, request, editor, level, workspace, project, launcher_platform):
- """
- Please review the hydra script run by this test for more specific test info.
- Tests the following Atom components and verifies all "expected_lines" appear in Editor.log:
- 1. Reflection Probe
- """
- cfg_args = [level]
-
- expected_lines = [
- # Reflection Probe Component
- "Reflection Probe Entity successfully created",
- "Reflection Probe_test: Component added to the entity: True",
- "Reflection Probe_test: Component removed after UNDO: True",
- "Reflection Probe_test: Component added after REDO: True",
- "Reflection Probe_test: Entered game mode: True",
- "Reflection Probe_test: Exit game mode: True",
- "Reflection Probe_test: Entity disabled initially: True",
- "Reflection Probe_test: Entity enabled after adding required components: True",
- "Reflection Probe_test: Cubemap is generated: True",
- "Reflection Probe_test: Entity is hidden: True",
- "Reflection Probe_test: Entity is shown: True",
- "Reflection Probe_test: Entity deleted: True",
- "Reflection Probe_test: UNDO entity deletion works: True",
- "Reflection Probe_test: REDO entity deletion works: True",
- ]
-
- hydra.launch_and_validate_results(
- request,
- TEST_DIRECTORY,
- editor,
- "hydra_AtomEditorComponents_AddedToEntity.py",
- timeout=120,
- expected_lines=expected_lines,
- unexpected_lines=[],
- halt_on_unexpected=True,
- null_renderer=True,
- cfg_args=cfg_args,
- )
+
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+@pytest.mark.parametrize("level", ["auto_test"])
+class TestAtomEditorComponentsMain(object):
+ """Holds tests for Atom components."""
+
+ @pytest.mark.test_case_id("C34525095")
+ def test_AtomEditorComponents_LightComponent(
+ self, request, editor, workspace, project, launcher_platform, level):
+ """
+ Please review the hydra script run by this test for more specific test info.
+ Tests that the Light component has the expected property options available to it.
+ """
+ cfg_args = [level]
+
+ expected_lines = [
+ "light_entity Entity successfully created",
+ "Entity has a Light component",
+ "light_entity_test: Component added to the entity: True",
+ f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
+ "Controller|Configuration|Shadows|Enable shadow set to True",
+ "light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
+ "Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
+ "Controller|Configuration|Shadows|Filtering sample count set to 4",
+ "Controller|Configuration|Shadows|Filtering sample count set to 64",
+ "Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
+ "Controller|Configuration|Shadows|ESM exponent set to 50.0",
+ "Controller|Configuration|Shadows|ESM exponent set to 5000.0",
+ "Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
+ f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
+ f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
+ f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
+ "light_entity Controller|Configuration|Fast approximation: SUCCESS",
+ "light_entity Controller|Configuration|Both directions: SUCCESS",
+ f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
+ f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
+ f"which matches {LIGHT_TYPES['simple_point']}",
+ "Controller|Configuration|Attenuation radius|Mode set to 0",
+ "Controller|Configuration|Attenuation radius|Radius set to 100.0",
+ f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
+ f"which matches {LIGHT_TYPES['simple_spot']}",
+ "Controller|Configuration|Shutters|Outer angle set to 45.0",
+ "Controller|Configuration|Shutters|Outer angle set to 90.0",
+ "light_entity_test: Component added to the entity: True",
+ "Light component test (non-GPU) completed.",
+ ]
+
+ unexpected_lines = ["Traceback (most recent call last):"]
+
+ hydra.launch_and_validate_results(
+ request,
+ TEST_DIRECTORY,
+ editor,
+ "hydra_AtomEditorComponents_LightComponent.py",
+ timeout=120,
+ expected_lines=expected_lines,
+ unexpected_lines=unexpected_lines,
+ halt_on_unexpected=True,
+ null_renderer=True,
+ cfg_args=cfg_args,
+ )
+
@pytest.mark.parametrize("project", ["AutomatedTesting"])
@pytest.mark.parametrize("launcher_platform", ['windows_generic'])
@@ -119,8 +140,6 @@ class TestMaterialEditorBasicTests(object):
"Save All worked as expected: True",
]
unexpected_lines = [
- # "Trace::Assert",
- # "Trace::Error",
"Traceback (most recent call last):"
]
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..41ffaa0ce1 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py
@@ -42,12 +42,14 @@ class AtomComponentProperties:
Bloom component properties. Requires PostFX Layer component.
- 'requires' a list of component names as strings required by this component.
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
+ - 'Enable Bloom' Toggle active state of the component True/False
:param property: From the last element of the property tree path. Default 'name' for component name string.
:return: Full property path OR component name if no property specified.
"""
properties = {
'name': 'Bloom',
'requires': [AtomComponentProperties.postfx_layer()],
+ 'Enable Bloom': 'Controller|Configuration|Enable Bloom',
}
return properties[property]
@@ -212,12 +214,14 @@ class AtomComponentProperties:
HDR Color Grading component properties. Requires PostFX Layer component.
- 'requires' a list of component names as strings required by this component.
Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n
+ - 'Enable HDR color grading' Toggle active state of the component True/False
:param property: From the last element of the property tree path. Default 'name' for component name string.
:return: Full property path OR component name if no property specified.
"""
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_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
deleted file mode 100644
index bbc8463152..0000000000
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
+++ /dev/null
@@ -1,238 +0,0 @@
-"""
-Copyright (c) Contributors to the Open 3D Engine Project.
-For complete copyright and license terms please see the LICENSE at the root of this distribution.
-
-SPDX-License-Identifier: Apache-2.0 OR MIT
-"""
-
-import os
-import sys
-
-import azlmbr.math as math
-import azlmbr.bus as bus
-import azlmbr.paths
-import azlmbr.asset as asset
-import azlmbr.entity as entity
-import azlmbr.legacy.general as general
-import azlmbr.editor as editor
-import azlmbr.render as render
-
-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.utils import TestHelper
-
-
-def run():
- """
- Summary:
- The below common tests are done for each of the components.
- 1) Addition of component to the entity
- 2) UNDO/REDO of addition of component
- 3) Enter/Exit game mode
- 4) Hide/Show entity containing component
- 5) Deletion of component
- 6) UNDO/REDO of deletion of component
- Some additional tests for specific components include
- 1) Assigning value to some properties of each component
- 2) Verifying if the component is activated only when the required components are added
-
- Expected Result:
- 1) Component can be added to an entity.
- 2) The addition of component can be undone and redone.
- 3) Game mode can be entered/exited without issue.
- 4) Entity with component can be hidden/shown.
- 5) Component can be deleted.
- 6) The deletion of component can be undone and redone.
- 7) Component is activated only when the required components are added
- 8) Values can be assigned to the properties of the component
-
- :return: None
- """
-
- def create_entity_undo_redo_component_addition(component_name):
- new_entity = hydra.Entity(f"{component_name}")
- new_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), [component_name])
- general.log(f"{component_name}_test: Component added to the entity: "
- f"{hydra.has_components(new_entity.id, [component_name])}")
-
- # undo component addition
- general.undo()
- TestHelper.wait_for_condition(lambda: not hydra.has_components(new_entity.id, [component_name]), 2.0)
- general.log(f"{component_name}_test: Component removed after UNDO: "
- f"{not hydra.has_components(new_entity.id, [component_name])}")
-
- # redo component addition
- general.redo()
- TestHelper.wait_for_condition(lambda: hydra.has_components(new_entity.id, [component_name]), 2.0)
- general.log(f"{component_name}_test: Component added after REDO: "
- f"{hydra.has_components(new_entity.id, [component_name])}")
-
- return new_entity
-
- def verify_enter_exit_game_mode(component_name):
- general.enter_game_mode()
- TestHelper.wait_for_condition(lambda: general.is_in_game_mode(), 2.0)
- general.log(f"{component_name}_test: Entered game mode: {general.is_in_game_mode()}")
- general.exit_game_mode()
- TestHelper.wait_for_condition(lambda: not general.is_in_game_mode(), 2.0)
- general.log(f"{component_name}_test: Exit game mode: {not general.is_in_game_mode()}")
-
- def verify_hide_unhide_entity(component_name, entity_obj):
-
- def is_entity_hidden(entity_id):
- return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", entity_id)
-
- editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, False)
- general.idle_wait_frames(1)
- general.log(f"{component_name}_test: Entity is hidden: {is_entity_hidden(entity_obj.id)}")
- editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, True)
- general.idle_wait_frames(1)
- general.log(f"{component_name}_test: Entity is shown: {not is_entity_hidden(entity_obj.id)}")
-
- def verify_deletion_undo_redo(component_name, entity_obj):
- editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", entity_obj.id)
- TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0)
- general.log(f"{component_name}_test: Entity deleted: {not hydra.find_entity_by_name(entity_obj.name)}")
-
- general.undo()
- TestHelper.wait_for_condition(lambda: hydra.find_entity_by_name(entity_obj.name) is not None, 2.0)
- general.log(f"{component_name}_test: UNDO entity deletion works: "
- f"{hydra.find_entity_by_name(entity_obj.name) is not None}")
-
- general.redo()
- TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0)
- general.log(f"{component_name}_test: REDO entity deletion works: "
- f"{not hydra.find_entity_by_name(entity_obj.name)}")
-
- def verify_required_component_addition(entity_obj, components_to_add, component_name):
-
- def is_component_enabled(entity_componentid_pair):
- return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", entity_componentid_pair)
-
- general.log(
- f"{component_name}_test: Entity disabled initially: "
- f"{not is_component_enabled(entity_obj.components[0])}")
- for component in components_to_add:
- entity_obj.add_component(component)
- TestHelper.wait_for_condition(lambda: is_component_enabled(entity_obj.components[0]), 2.0)
- general.log(
- f"{component_name}_test: Entity enabled after adding "
- f"required components: {is_component_enabled(entity_obj.components[0])}"
- )
-
- def verify_set_property(entity_obj, path, value):
- entity_obj.get_set_test(0, path, value)
-
- # Verify cubemap generation
- def verify_cubemap_generation(component_name, entity_obj):
- # Initially Check if the component has Reflection Probe component
- if not hydra.has_components(entity_obj.id, ["Reflection Probe"]):
- raise ValueError(f"Given entity {entity_obj.name} has no Reflection Probe component")
- render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", entity_obj.id)
-
- def get_value():
- hydra.get_component_property_value(entity_obj.components[0], "Cubemap|Baked Cubemap Path")
-
- TestHelper.wait_for_condition(lambda: get_value() != "", 20.0)
- general.log(f"{component_name}_test: Cubemap is generated: {get_value() != ''}")
-
- # Wait for Editor idle loop before executing Python hydra scripts.
- TestHelper.init_idle()
-
- # Delete all existing entities initially
- search_filter = azlmbr.entity.SearchFilter()
- all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
- editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities)
-
- class ComponentTests:
- """Test launcher for each component."""
- def __init__(self, component_name, *additional_tests):
- self.component_name = component_name
- self.additional_tests = additional_tests
- self.run_component_tests()
-
- def run_component_tests(self):
- # Run common and additional tests
- entity_obj = create_entity_undo_redo_component_addition(self.component_name)
-
- # Enter/Exit game mode test
- verify_enter_exit_game_mode(self.component_name)
-
- # Any additional tests are executed here
- for test in self.additional_tests:
- test(entity_obj)
-
- # Hide/Unhide entity test
- verify_hide_unhide_entity(self.component_name, entity_obj)
-
- # Deletion/Undo/Redo test
- verify_deletion_undo_redo(self.component_name, entity_obj)
-
- # DepthOfField Component
- camera_entity = hydra.Entity("camera_entity")
- camera_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), ["Camera"])
- depth_of_field = "DepthOfField"
- ComponentTests(
- depth_of_field,
- lambda entity_obj: verify_required_component_addition(entity_obj, ["PostFX Layer"], depth_of_field),
- lambda entity_obj: verify_set_property(
- entity_obj, "Controller|Configuration|Camera Entity", camera_entity.id))
-
- # Decal Component
- material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
- material_asset = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
- ComponentTests(
- "Decal", lambda entity_obj: verify_set_property(
- entity_obj, "Controller|Configuration|Material", material_asset))
-
- # Directional Light Component
- ComponentTests(
- "Directional Light",
- lambda entity_obj: verify_set_property(
- entity_obj, "Controller|Configuration|Shadow|Camera", camera_entity.id))
-
- # Exposure Control Component
- ComponentTests(
- "Exposure Control", lambda entity_obj: verify_required_component_addition(
- entity_obj, ["PostFX Layer"], "Exposure Control"))
-
- # Global Skylight (IBL) Component
- diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
- diffuse_image_asset = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", diffuse_image_path, math.Uuid(), False)
- specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage")
- specular_image_asset = asset.AssetCatalogRequestBus(
- bus.Broadcast, "GetAssetIdByPath", specular_image_path, math.Uuid(), False)
- ComponentTests(
- "Global Skylight (IBL)",
- lambda entity_obj: verify_set_property(
- entity_obj, "Controller|Configuration|Diffuse Image", diffuse_image_asset),
- lambda entity_obj: verify_set_property(
- entity_obj, "Controller|Configuration|Specular Image", specular_image_asset))
-
- # Physical Sky Component
- ComponentTests("Physical Sky")
-
- # PostFX Layer Component
- ComponentTests("PostFX Layer")
-
- # PostFX Radius Weight Modifier Component
- ComponentTests("PostFX Radius Weight Modifier")
-
- # Light Component
- ComponentTests("Light")
-
- # Display Mapper Component
- ComponentTests("Display Mapper")
-
- # Reflection Probe Component
- reflection_probe = "Reflection Probe"
- ComponentTests(
- reflection_probe,
- lambda entity_obj: verify_required_component_addition(entity_obj, ["Box Shape"], reflection_probe),
- lambda entity_obj: verify_cubemap_generation(reflection_probe, entity_obj),)
-
-if __name__ == "__main__":
- run()
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py
new file mode 100644
index 0000000000..56b22eb20d
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py
@@ -0,0 +1,189 @@
+"""
+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")
+ bloom_creation = (
+ "Bloom Entity successfully created",
+ "Bloom Entity failed to be created")
+ bloom_component = (
+ "Entity has a Bloom component",
+ "Entity failed to find Bloom component")
+ bloom_disabled = (
+ "Bloom component disabled",
+ "Bloom component was not disabled")
+ postfx_layer_component = (
+ "Entity has a PostFX Layer component",
+ "Entity did not have an PostFX Layer component")
+ bloom_enabled = (
+ "Bloom component enabled",
+ "Bloom component was not enabled")
+ enable_bloom_parameter_enabled = (
+ "Enable Bloom parameter enabled",
+ "Enable Bloom 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_Bloom_AddedToEntity():
+ """
+ Summary:
+ Tests the Bloom 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 Bloom entity with no components.
+ 2) Add Bloom component to Bloom entity.
+ 3) UNDO the entity creation and component addition.
+ 4) REDO the entity creation and component addition.
+ 5) Verify Bloom component not enabled.
+ 6) Add PostFX Layer component since it is required by the Bloom component.
+ 7) Verify Bloom component is enabled.
+ 8) Enable the "Enable Bloom" parameter.
+ 9) Enter/Exit game mode.
+ 10) Test IsHidden.
+ 11) Test IsVisible.
+ 12) Delete Bloom 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 Bloom entity with no components.
+ bloom_entity = EditorEntity.create_editor_entity(AtomComponentProperties.bloom())
+ Report.critical_result(Tests.bloom_creation, bloom_entity.exists())
+
+ # 2. Add Bloom component to Bloom entity.
+ bloom_component = bloom_entity.add_component(AtomComponentProperties.bloom())
+ Report.critical_result(Tests.bloom_component, bloom_entity.has_component(AtomComponentProperties.bloom()))
+
+ # 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 bloom_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, bloom_entity.exists())
+
+ # 5. Verify Bloom component not enabled.
+ Report.result(Tests.bloom_disabled, not bloom_component.is_enabled())
+
+ # 6. Add PostFX Layer component since it is required by the Bloom component.
+ bloom_entity.add_component(AtomComponentProperties.postfx_layer())
+ Report.result(
+ Tests.postfx_layer_component,
+ bloom_entity.has_component(AtomComponentProperties.postfx_layer()))
+
+ # 7. Verify Bloom component is enabled.
+ Report.result(Tests.bloom_enabled, bloom_component.is_enabled())
+
+ # 8. Enable the "Enable Bloom" parameter.
+ bloom_component.set_component_property_value(AtomComponentProperties.bloom('Enable Bloom'), True)
+ Report.result(
+ Tests.enable_bloom_parameter_enabled,
+ bloom_component.get_component_property_value(AtomComponentProperties.bloom('Enable Bloom')) 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.
+ bloom_entity.set_visibility_state(False)
+ Report.result(Tests.is_hidden, bloom_entity.is_hidden() is True)
+
+ # 11. Test IsVisible.
+ bloom_entity.set_visibility_state(True)
+ general.idle_wait_frames(1)
+ Report.result(Tests.is_visible, bloom_entity.is_visible() is True)
+
+ # 12. Delete Bloom entity.
+ bloom_entity.delete()
+ Report.result(Tests.entity_deleted, not bloom_entity.exists())
+
+ # 13. UNDO deletion.
+ general.undo()
+ Report.result(Tests.deletion_undo, bloom_entity.exists())
+
+ # 14. REDO deletion.
+ general.redo()
+ Report.result(Tests.deletion_redo, not bloom_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_Bloom_AddedToEntity)
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_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/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/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/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/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 0277abe60d..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
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/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/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)
+ return AZ::Uuid::CreateNull();
+ }
+
+ 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())
{
- 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);
+ continue;
+ }
+ if (pair.second.size() == 1)
+ {
+ return pair.second[0];
+ }
- 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;
- }
+ // 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/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss
index de35f91678..a7d3949527 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss
@@ -11,7 +11,6 @@ OutlinerWidget #m_display_options
{
qproperty-icon: url(:/Menu/menu.svg);
qproperty-iconSize: 16px 16px;
- qproperty-flat: true;
}
OutlinerWidget QWidget[PulseHighlight="true"]
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/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;
+ struct StackFrame;
- namespace Platform
- {
+ 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/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;
- }
+ ::SetUnhandledExceptionFilter(g_previousExceptionHandler);
+ g_previousExceptionHandler = NULL;
}
+ }
- bool AttachDebugger()
+ bool AttachDebugger()
+ {
+ if (IsDebuggerPresent())
{
- 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;
+ return true;
}
- void DebugBreak()
+ // 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)
{
- __debugbreak();
+ ::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 Terminate(int exitCode)
+ {
+ TerminateProcess(GetCurrentProcess(), exitCode);
+ }
- void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
+ void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
+ {
+ AZStd::fixed_wstring tmpW;
+ if(window)
{
- AZStd::fixed_wstring tmpW;
- if(window)
- {
- AZStd::to_wstring(tmpW, window);
- tmpW += L": ";
- OutputDebugStringW(tmpW.c_str());
- tmpW.clear();
- }
- AZStd::to_wstring(tmpW, message);
+ 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/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/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/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp
index c6f481b65b..a3381dabb8 100644
--- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp
+++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp
@@ -10,6 +10,8 @@
#include
#include
+#include
+
#include
#include
@@ -24,14 +26,20 @@ namespace AzFramework::AssetSystem::Platform
AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory };
// In Mac the Editor and game is within a bundle, so the path to the sibling app
// has to go up from the Contents/MacOS folder the binary is in
- assetProcessorPath /= "../../../AssetProcessor.app";
+ assetProcessorPath /= "../../../AssetProcessor.app/Contents/MacOS/AssetProcessor";
assetProcessorPath = assetProcessorPath.LexicallyNormal();
if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str()))
{
- // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure.
- assetProcessorPath =
- AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app";
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ if (AZ::IO::FixedMaxPath installedBinariesPath;
+ settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
+ {
+ // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure.
+ assetProcessorPath = AZ::IO::FixedMaxPath{ engineRoot } / installedBinariesPath / "AssetProcessor.app/Contents/MacOS/AssetProcessor";
+ }
+ }
if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str()))
{
@@ -39,23 +47,21 @@ namespace AzFramework::AssetSystem::Platform
}
}
- auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"(open -g "%s" --args --start-hidden)", assetProcessorPath.c_str());
+ AZStd::string commandLineParams;
// Add the engine path to the launch command if not empty
if (!engineRoot.empty())
{
- fullLaunchCommand += R"( --engine-path=")";
- fullLaunchCommand += engineRoot;
- fullLaunchCommand += '"';
+ commandLineParams += AZStd::string::format("\"--engine-path=\"%s\"\"", engineRoot.data());
}
- // Add the active project path to the launch command if not empty
if (!projectPath.empty())
{
- fullLaunchCommand += R"( --project-path=")";
- fullLaunchCommand += projectPath;
- fullLaunchCommand += '"';
+ commandLineParams += AZStd::string::format(" \"--regset=/Amazon/AzCore/Bootstrap/project_path=\"%s\"\"", projectPath.data());
}
- return system(fullLaunchCommand.c_str()) == 0;
+ AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
+ processLaunchInfo.m_processExecutableString = AZStd::move(assetProcessorPath.Native());
+ processLaunchInfo.m_commandlineParameters = commandLineParams;
+ return AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
}
}
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 6957844452..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()
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/EntityOutliner.qss b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss
index b3c5882334..93460f8816 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss
@@ -10,7 +10,6 @@ AzToolsFramework--EntityOutlinerWidget #m_display_options
{
qproperty-icon: url(:/stylesheet/img/UI20/menu-centered.svg);
qproperty-iconSize: 16px 16px;
- qproperty-flat: true;
}
AzToolsFramework--EntityOutlinerWidget QTreeView
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/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/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/StlUtils.h b/Code/Legacy/CryCommon/StlUtils.h
index f5128a564f..ccbc854dc3 100644
--- a/Code/Legacy/CryCommon/StlUtils.h
+++ b/Code/Legacy/CryCommon/StlUtils.h
@@ -96,47 +96,6 @@ unsigned countElements (const std::vector& arrT, const T& x)
*/
namespace stl
{
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Compare member of class/struct.
- //
- // e.g. Sort Vec3s by x component
- //
- // std::sort(vec3s.begin(), vec3s.end(), stl::member_compare());
- //
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- template >
- struct member_compare
- {
- inline bool operator () (const OWNER_TYPE& lhs, const OWNER_TYPE& rhs) const
- {
- return EQUALITY()(lhs.*MEMBER_PTR, rhs.*MEMBER_PTR);
- }
- };
-
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Compare member of class/struct against parameter.
- //
- // e.g. Find Vec3 with x component less than 1.0
- //
- // std::find_if(vec3s.begin(), vec3s.end(), stl::member_compare_param(1.0f));
- //
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- template >
- struct member_compare_param
- {
- inline member_compare_param(const MEMBER_TYPE& _value)
- : value(_value)
- {
- }
-
- inline bool operator () (const OWNER_TYPE& rhs) const
- {
- return EQUALITY()(rhs.*MEMBER_PTR, value);
- }
-
- const MEMBER_TYPE& value;
- };
-
//////////////////////////////////////////////////////////////////////////
//! Searches the given entry in the map by key, and if there is none, returns the default value
//////////////////////////////////////////////////////////////////////////
@@ -154,48 +113,6 @@ namespace stl
}
}
- //////////////////////////////////////////////////////////////////////////
- //! Inserts and returns a reference to the given value in the map, or returns the current one if it's already there.
- //////////////////////////////////////////////////////////////////////////
- template
- inline typename Map::mapped_type& map_insert_or_get(Map& mapKeyToValue, const typename Map::key_type& key, const typename Map::mapped_type& defValue = typename Map::mapped_type())
- {
- auto&& iresult = mapKeyToValue.insert(typename Map::value_type(key, defValue));
- return iresult.first->second;
- }
-
- // searches the given entry in the map by key, and if there is none, returns the default value
- // The values are taken/returned in REFERENCEs rather than values
- template
- inline mapped_type& find_in_map_ref(std::map& mapKeyToValue, const Key& key, mapped_type& valueDefault)
- {
- typedef std::map Map;
- typename Map::iterator it = mapKeyToValue.find (key);
- if (it == mapKeyToValue.end())
- {
- return valueDefault;
- }
- else
- {
- return it->second;
- }
- }
-
- template
- inline const mapped_type& find_in_map_ref(const std::map& mapKeyToValue, const Key& key, const mapped_type& valueDefault)
- {
- typedef std::map Map;
- typename Map::const_iterator it = mapKeyToValue.find (key);
- if (it == mapKeyToValue.end())
- {
- return valueDefault;
- }
- else
- {
- return it->second;
- }
- }
-
//////////////////////////////////////////////////////////////////////////
//! Fills vector with contents of map.
//////////////////////////////////////////////////////////////////////////
@@ -210,20 +127,6 @@ namespace stl
}
}
- //////////////////////////////////////////////////////////////////////////
- //! Fills vector with contents of set.
- //////////////////////////////////////////////////////////////////////////
- template
- inline void set_to_vector(const Set& theSet, Vector& array)
- {
- array.resize(0);
- array.reserve(theSet.size());
- for (typename Set::const_iterator it = theSet.begin(); it != theSet.end(); ++it)
- {
- array.push_back(*it);
- }
- }
-
//////////////////////////////////////////////////////////////////////////
//! Find and erase element from container.
// @return true if item was find and erased, false if item not found.
@@ -312,48 +215,6 @@ namespace stl
return false;
}
- //////////////////////////////////////////////////////////////////////////
- //! Push back to container unique element.
- // @return true if item added, false overwise.
- template
- inline bool push_back_unique_if(CONTAINER& container, const PREDICATE& predicate, const VALUE& value)
- {
- typename CONTAINER::iterator end = container.end();
-
- if (AZStd::find_if(container.begin(), end, predicate) == end)
- {
- container.push_back(value);
-
- return true;
- }
- else
- {
- return false;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////
- //! Push back to container contents of another container
- template
- inline void push_back_range(Container& container, Iter begin, Iter end)
- {
- for (Iter it = begin; it != end; ++it)
- {
- container.push_back(*it);
- }
- }
-
- //////////////////////////////////////////////////////////////////////////
- //! Push back to container contents of another container, if not already present
- template
- inline void push_back_range_unique(Container& container, Iter begin, Iter end)
- {
- for (Iter it = begin; it != end; ++it)
- {
- push_back_unique(container, *it);
- }
- }
-
//////////////////////////////////////////////////////////////////////////
//! Find element in container.
// @return true if item found.
@@ -373,107 +234,6 @@ namespace stl
return (it == last || value != *it) ? last : it;
}
- //////////////////////////////////////////////////////////////////////////
- //! Find element in a sorted container using binary search with logarithmic efficiency.
- // @return true if item was inserted.
- template
- inline bool binary_insert_unique(Container& container, const Value& value)
- {
- typename Container::iterator it = std::lower_bound(container.begin(), container.end(), value);
- if (it != container.end())
- {
- if (*it == value)
- {
- return false;
- }
- container.insert(it, value);
- }
- else
- {
- container.insert(container.end(), value);
- }
- return true;
- }
- //////////////////////////////////////////////////////////////////////////
- //! Find element in a sorted container using binary search with logarithmic efficiency.
- // and erases if element found.
- // @return true if item was erased.
- template
- inline bool binary_erase(Container& container, const Value& value)
- {
- typename Container::iterator it = std::lower_bound(container.begin(), container.end(), value);
- if (it != container.end() && *it == value)
- {
- container.erase(it);
- return true;
- }
- return false;
- }
-
- template
- ItT remove_from_heap(ItT begin, ItT end, ItT at, Func order)
- {
- using std::swap;
-
- --end;
- if (at == end)
- {
- return at;
- }
-
- size_t idx = std::distance(begin, at);
- swap(*end, *at);
-
- size_t length = std::distance(begin, end);
- size_t parent, child;
-
- if (idx > 0 && order(*(begin + idx / 2), *(begin + idx)))
- {
- do
- {
- parent = idx / 2;
- swap(*(begin + idx), *(begin + parent));
- idx = parent;
-
- if (idx == 0 || order(*(begin + idx), *(begin + idx / 2)))
- {
- return end;
- }
- }
- while (true);
- }
- else
- {
- do
- {
- child = idx * 2 + 1;
- if (child >= length)
- {
- return end;
- }
-
- ItT left = begin + child;
- ItT right = begin + child + 1;
-
- if (right < end && order(*left, *right))
- {
- ++child;
- }
-
- if (order(*(begin + child), *(begin + idx)))
- {
- return end;
- }
-
- swap(*(begin + child), *(begin + idx));
- idx = child;
- }
- while (true);
- }
-
- return end;
- }
-
struct container_object_deleter
{
template
@@ -506,18 +266,6 @@ namespace stl
return type.c_str();
}
- //////////////////////////////////////////////////////////////////////////
- //! Case sensetive less key for any type convertable to const char*.
- //////////////////////////////////////////////////////////////////////////
- template
- struct less_strcmp
- {
- bool operator()(const Type& left, const Type& right) const
- {
- return strcmp(constchar_cast(left), constchar_cast(right)) < 0;
- }
- };
-
//////////////////////////////////////////////////////////////////////////
//! Case insensetive less key for any type convertable to const char*.
template
@@ -690,89 +438,4 @@ namespace stl
stl::free_container(container);
}
};
-
- template
- inline void for_each_array(T (&buffer)[Length], Func func)
- {
- std::for_each(&buffer[0], &buffer[Length], func);
- }
-
- template
- inline void for_each_array(StaticInstance(&buffer)[Length], Func func)
- {
- for (size_t idx = 0; idx < Length; ++idx)
- {
- func(*buffer[idx]);
- }
- }
-
- template
- inline void destruct(T* p)
- {
- p->~T();
- }
-}
-
-#define DEFINE_INTRUSIVE_LINKED_LIST(Class) \
- template<> \
- Class * stl::intrusive_linked_list_node::m_root_intrusive = nullptr;
-
-// define the maplikestruct, used to approximate the memory requirements for a map node
-namespace stl
-{
- struct MapLikeStruct
- {
- bool color;
- void* parent;
- void* left;
- void* right;
- };
-}
-template
-unsigned sizeOfMap(Map& map)
-{
- unsigned size = 0;
- for (typename Map::iterator it = map.begin(); it != map.end(); it++)
- {
- typename Map::mapped_type& T = it->second;
- size += T.Size();
- }
- size += map.size() * sizeof(stl::MapLikeStruct);
- return size;
-}
-template
-unsigned sizeOfMapStr(Map& map)
-{
- unsigned size = 0;
- for (typename Map::iterator it = map.begin(); it != map.end(); it++)
- {
- typename Map::mapped_type& T = it->second;
- size += T.capacity();
- }
- size += map.size() * sizeof(stl::MapLikeStruct);
- return size;
-}
-template
-unsigned sizeOfMapP(Map& map)
-{
- unsigned size = 0;
- for (typename Map::iterator it = map.begin(); it != map.end(); it++)
- {
- typename Map::mapped_type& T = it->second;
- size += T->Size();
- }
- size += map.size() * sizeof(stl::MapLikeStruct);
- return size;
-}
-template
-unsigned sizeOfMapS(Map& map)
-{
- unsigned size = 0;
- for (typename Map::iterator it = map.begin(); it != map.end(); it++)
- {
- typename Map::mapped_type& T = it->second;
- size += sizeof(T);
- }
- size += map.size() * sizeof(stl::MapLikeStruct);
- return size;
}
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..65facba4dd 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;
@@ -516,8 +509,6 @@ void CSystem::ShutDown()
ShutdownFileSystem();
- ShutdownModuleLibraries();
-
EBUS_EVENT(CrySystemEventBus, OnCrySystemPostShutdown);
}
@@ -697,31 +688,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 +1221,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..a10c1f8ed8 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;
@@ -324,8 +303,6 @@ public:
void SetVersionInfo(const char* const szVersion);
#endif
- void ShutdownModuleLibraries();
-
#if defined(WIN32)
friend LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#endif
@@ -344,8 +321,6 @@ private:
// Release all resources.
void ShutDown();
- bool LoadEngineDLLs();
-
//! @name Initialization routines
//@{
bool InitConsole();
@@ -361,11 +336,8 @@ private:
void CreateSystemVars();
void CreateAudioVars();
- AZStd::unique_ptr LoadDLL(const char* dllName);
-
void FreeLib(AZStd::unique_ptr& hLibModule);
- bool UnloadDLL(const char* dllName);
void QueryVersionInfo();
void LogVersion();
void LogBuildInfo();
@@ -380,8 +352,6 @@ private:
void AddCVarGroupDirectory(const AZStd::string& sPath) override;
- AZStd::unique_ptr LoadDynamiclibrary(const char* dllName) const;
-
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEM_H_SECTION_3
#include AZ_RESTRICTED_FILE(System_h)
@@ -437,9 +407,6 @@ private: // ------------------------------------------------------
bool m_bDrawConsole; //!< Set to true if OK to draw the console.
bool m_bDrawUI; //!< Set to true if OK to draw UI.
-
- std::map > m_moduleDLLHandles;
-
//! current active process
IProcess* m_pProcess;
@@ -564,8 +531,6 @@ private: // ------------------------------------------------------
ESystemConfigSpec m_nMaxConfigSpec;
ESystemConfigPlatform m_ConfigPlatform;
- CProfilingSystem m_ProfilingSystem;
-
// Pause mode.
bool m_bPaused;
bool m_bNoUpdate;
@@ -588,9 +553,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..d9ba3bb4c9 100644
--- a/Code/Legacy/CrySystem/SystemInit.cpp
+++ b/Code/Legacy/CrySystem/SystemInit.cpp
@@ -12,7 +12,6 @@
#if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
#undef AZ_RESTRICTED_SECTION
-#define SYSTEMINIT_CPP_SECTION_1 1
#define SYSTEMINIT_CPP_SECTION_2 2
#define SYSTEMINIT_CPP_SECTION_3 3
#define SYSTEMINIT_CPP_SECTION_4 4
@@ -70,9 +69,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
@@ -171,34 +167,6 @@ void CryEngineSignalHandler(int signal)
#define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml"
-//////////////////////////////////////////////////////////////////////////
-#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"
-# define DLL_INITFUNC_3DENGINE "CreateCry3DEngine"
-# define DLL_INITFUNC_UI "CreateLyShineInterface"
-#define AZ_RESTRICTED_SECTION_IMPLEMENTED
-#elif defined(AZ_RESTRICTED_PLATFORM)
-#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_1
-#include AZ_RESTRICTED_FILE(SystemInit_cpp)
-#endif
-#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
-# define DLL_INITFUNC_PHYSIC (LPCSTR)1
-# define DLL_INITFUNC_FONT (LPCSTR)1
-# define DLL_INITFUNC_3DENGINE (LPCSTR)1
-# define DLL_INITFUNC_UI (LPCSTR)1
-#endif
-
#define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow()
#ifdef WIN32
@@ -292,96 +260,6 @@ static void CmdCrashTest(IConsoleCmdArgs* pArgs)
}
AZ_POP_DISABLE_WARNING
-//////////////////////////////////////////////////////////////////////////
-struct SysSpecOverrideSink
- : public ILoadConfigurationEntrySink
-{
- virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup)
- {
- ICVar* pCvar = gEnv->pConsole->GetCVar(szKey);
-
- if (pCvar)
- {
- const bool wasNotInConfig = ((pCvar->GetFlags() & VF_WASINCONFIG) == 0);
- bool applyCvar = wasNotInConfig;
- if (applyCvar == false)
- {
- // Special handling for sys_spec_full
- if (azstricmp(szKey, "sys_spec_full") == 0)
- {
- // If it is set to 0 then ignore this request to set to something else
- // If it is set to 0 then the user wants to changes system spec settings in system.cfg
- if (pCvar->GetIVal() != 0)
- {
- applyCvar = true;
- }
- }
- else
- {
- // This could bypass the restricted cvar checks that exist elsewhere depending on
- // the calling code so we also need check here before setting.
- bool isConst = pCvar->IsConstCVar();
- bool isCheat = ((pCvar->GetFlags() & (VF_CHEAT | VF_CHEAT_NOCHECK | VF_CHEAT_ALWAYS_CHECK)) != 0);
- bool isReadOnly = ((pCvar->GetFlags() & VF_READONLY) != 0);
- bool isDeprecated = ((pCvar->GetFlags() & VF_DEPRECATED) != 0);
- bool allowApplyCvar = true;
-
- if ((isConst || isCheat || isReadOnly) || isDeprecated)
- {
- allowApplyCvar = !isDeprecated && (gEnv->pSystem->IsDevMode()) || (gEnv->IsEditor());
- }
-
- if ((allowApplyCvar) || ALLOW_CONST_CVAR_MODIFICATIONS)
- {
- applyCvar = true;
- }
- }
- }
-
- if (applyCvar)
- {
- pCvar->Set(szValue);
- }
- else
- {
- CryLogAlways("NOT VF_WASINCONFIG Ignoring cvar '%s' new value '%s' old value '%s' group '%s'", szKey, szValue, pCvar->GetString(), szGroup);
- }
- }
- else
- {
- CryLogAlways("Can't find cvar '%s' value '%s' group '%s'", szKey, szValue, szGroup);
- }
- }
-};
-
-#if !defined(CONSOLE)
-struct SysSpecOverrideSinkConsole
- : public ILoadConfigurationEntrySink
-{
- virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup)
- {
- // Ignore platform-specific cvars that should just be executed on the console
- if (azstricmp(szGroup, "Platform") == 0)
- {
- return;
- }
-
- ICVar* pCvar = gEnv->pConsole->GetCVar(szKey);
- if (pCvar)
- {
- pCvar->Set(szValue);
- }
- else
- {
- // If the cvar doesn't exist, calling this function only saves the value in case it's registered later where
- // at that point it will be set from the stored value. This is required because otherwise registering the
- // cvar bypasses any callbacks and uses values directly from the cvar group files.
- gEnv->pConsole->LoadConfigVar(szKey, szValue);
- }
- }
-};
-#endif
-
static ESystemConfigPlatform GetDevicePlatform()
{
#if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX)
@@ -405,117 +283,6 @@ static ESystemConfigPlatform GetDevicePlatform()
#endif
}
-//////////////////////////////////////////////////////////////////////////
-#if !defined(AZ_MONOLITHIC_BUILD)
-
-AZStd::unique_ptr CSystem::LoadDynamiclibrary(const char* dllName) const
-{
- AZStd::unique_ptr handle = AZ::DynamicModuleHandle::Create(dllName);
-
- bool libraryLoaded = handle->Load(false);
- // We need to inject the environment first thing so that allocators are available immediately
- InjectEnvironmentFunction injectEnv = handle->GetFunction(INJECT_ENVIRONMENT_FUNCTION);
- if (injectEnv)
- {
- auto env = AZ::Environment::GetInstance();
- injectEnv(env);
- }
-
- if (!libraryLoaded)
- {
- handle.release();
- }
- return handle;
-}
-
-//////////////////////////////////////////////////////////////////////////
-AZStd::unique_ptr CSystem::LoadDLL(const char* dllName)
-{
- AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "Loading DLL: %s", dllName);
-
- AZStd::unique_ptr handle = LoadDynamiclibrary(dllName);
-
- if (!handle)
- {
-#if defined(LINUX) || defined(APPLE)
- AZ_Assert(false, "Error loading dylib: %s, error : %s\n", dllName, dlerror());
-#else
- AZ_Assert(false, "Error loading dll: %s, error code %d", dllName, GetLastError());
-#endif
- 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;
-}
-
-// TODO:DLL #endif //#if defined(AZ_HAS_DLL_SUPPORT) && !defined(AZ_MONOLITHIC_BUILD)
-#endif //if !defined(AZ_MONOLITHIC_BUILD)
-//////////////////////////////////////////////////////////////////////////
-bool CSystem::LoadEngineDLLs()
-{
- return true;
-}
-
-//////////////////////////////////////////////////////////////////////////
-bool CSystem::UnloadDLL(const char* dllName)
-{
- bool isSuccess = false;
-
- AZ::Crc32 key(dllName);
- AZStd::unique_ptr empty;
- AZStd::unique_ptr& hModule = stl::find_in_map_ref(m_moduleDLLHandles, key, empty);
- if ((hModule) && (hModule->IsLoaded()))
- {
- DetachEnvironmentFunction detachEnv = hModule->GetFunction(DETACH_ENVIRONMENT_FUNCTION);
- if (detachEnv)
- {
- detachEnv();
- }
-
- isSuccess = hModule->Unload();
- hModule.release();
- }
-
- return isSuccess;
-}
-
-//////////////////////////////////////////////////////////////////////////
-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();
- }
- iterator->second.release();
- }
-
- m_moduleDLLHandles.clear();
-
-#endif // !defined(AZ_MONOLITHIC_BUILD)
-}
-
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
bool CSystem::InitConsole()
@@ -649,7 +416,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 +471,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 +526,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 +546,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 +555,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 +1059,7 @@ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////
// Open basic pak files after intro movie playback started
//////////////////////////////////////////////////////////////////////////
- OpenBasicPaks();
+ OpenPlatformPaks();
//////////////////////////////////////////////////////////////////////////
// AUDIO
@@ -1714,8 +1445,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/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 6f15fa5ea2..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);
@@ -301,7 +302,6 @@ namespace AssetProcessor
if (!platformCodes.empty())
{
AZStd::string_view platform = platformCodes.front();
- constexpr AZ::u32 productSubID = 0;
for (size_t i = 0; i < AZStd::size(specializations); ++i)
{
const AZ::SettingsRegistryInterface::Specializations& specialization = specializations[i];
@@ -413,7 +413,8 @@ namespace AssetProcessor
return;
}
- outputPath += specialization.GetSpecialization(0); // Append configuration
+ AZStd::string_view specializationString(specialization.GetSpecialization(0));
+ outputPath += specializationString; // Append configuration
outputPath += ".setreg";
AZ::IO::SystemFile file;
@@ -430,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