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..a77f62caf2 100644
--- a/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp
+++ b/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
@@ -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/Blast/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt
index cb83fe5344..aea2562e0b 100644
--- a/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt
@@ -6,7 +6,11 @@
#
#
-if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
+ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
+
+include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_BLAST Traits
+
+if(PAL_TRAIT_BLAST_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::BlastTests_Main
TEST_SUITE main
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake
@@ -0,0 +1,9 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake
@@ -0,0 +1,9 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake
@@ -0,0 +1,9 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake
new file mode 100644
index 0000000000..28767237de
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake
@@ -0,0 +1,9 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED TRUE)
diff --git a/AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake b/AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake
new file mode 100644
index 0000000000..f91b18e9f1
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake
@@ -0,0 +1,9 @@
+#
+# Copyright (c) Contributors to the Open 3D Engine Project.
+# For complete copyright and license terms please see the LICENSE at the root of this distribution.
+#
+# SPDX-License-Identifier: Apache-2.0 OR MIT
+#
+#
+
+set(PAL_TRAIT_BLAST_TESTS_SUPPORTED FALSE)
diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
index fd3222ba83..bec49185bd 100644
--- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt
@@ -59,5 +59,8 @@ add_subdirectory(smoke)
## AWS ##
add_subdirectory(AWS)
+## Multiplayer ##
+add_subdirectory(Multiplayer)
+
## Integration tests for editor testing framework ##
add_subdirectory(editor_test_testing)
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/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/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..c5c3acd2f6 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
@@ -1686,6 +1687,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/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/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;
+
+ namespace Platform
{
- struct StackFrame;
-
- namespace Platform
- {
#if defined(AZ_ENABLE_DEBUG_TOOLS)
- bool AttachDebugger();
- bool IsDebuggerPresent();
- void HandleExceptions(bool isEnabled);
- void DebugBreak();
+ bool AttachDebugger();
+ bool IsDebuggerPresent();
+ void HandleExceptions(bool isEnabled);
+ void DebugBreak();
#endif
- void Terminate(int exitCode);
- }
+ void Terminate(int exitCode);
}
- using namespace AZ::Debug;
-
namespace DebugInternal
{
// other threads can trigger fatals and errors, but the same thread should not, to avoid stack overflow.
@@ -60,7 +55,7 @@ namespace AZ
// Globals
const int g_maxMessageLength = 4096;
static const char* g_dbgSystemWnd = "System";
- Trace Debug::g_tracer;
+ Trace g_tracer;
void* g_exceptionInfo = nullptr;
// Environment var needed to track ignored asserts across systems and disable native UI under certain conditions
@@ -616,4 +611,4 @@ namespace AZ
val.Set(level);
}
}
-} // namspace AZ
+} // namspace AZ::Debug
diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp
index 9728866fb6..9a465021c2 100644
--- a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp
@@ -156,7 +156,10 @@ namespace AZ
void StreamerComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
bool isEnabled = false;
- AZ::Debug::ProfilerRequestBus::BroadcastResult(isEnabled, &AZ::Debug::ProfilerRequests::IsActive);
+ if (auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); profilerSystem)
+ {
+ isEnabled = profilerSystem->IsActive();
+ }
if (isEnabled)
{
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl
index e228a19d68..8355f9bfe0 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathCommon_sse.inl
@@ -383,36 +383,36 @@ namespace AZ
AZ_MATH_INLINE bool CmpAllEq(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpNeq(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpEq(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllLt(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpGtEq(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpLt(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllLtEq(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpGt(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpLtEq(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllGt(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpLtEq(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpGt(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
AZ_MATH_INLINE bool CmpAllGtEq(__m128 arg1, __m128 arg2, int32_t mask)
{
- const __m128i compare = CastToInt(CmpLt(arg1, arg2));
- return (_mm_movemask_epi8(compare) & mask) == 0;
+ const __m128 compare = CmpGtEq(arg1, arg2);
+ return (_mm_movemask_ps(compare) & mask) == mask;
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl
index ecdcf40743..bb332c03a2 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec1_sse.inl
@@ -331,31 +331,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec1::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x000F);
+ // Only check the first bit for Vector1
+ return Sse::CmpAllEq(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0x000F);
+ return Sse::CmpAllLt(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0x000F);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0x000F);
+ return Sse::CmpAllGt(arg1, arg2, 0b0001);
}
AZ_MATH_INLINE bool Vec1::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0x000F);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b0001);
}
@@ -397,7 +398,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec1::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x000F);
+ return Sse::CmpAllEq(arg1, arg2, 0b0001);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl
index c890aa5eb7..90fb97e694 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec2_sse.inl
@@ -383,31 +383,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec2::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x00FF);
+ // Only check the first two bits for Vector2
+ return Sse::CmpAllEq(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0x00FF);
+ return Sse::CmpAllLt(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0x00FF);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0x00FF);
+ return Sse::CmpAllGt(arg1, arg2, 0b0011);
}
AZ_MATH_INLINE bool Vec2::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0x00FF);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b0011);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl
index a8ff962837..31e8d19d65 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec3_sse.inl
@@ -419,31 +419,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec3::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x0FFF);
+ // Only check the first three bits for Vector3
+ return Sse::CmpAllEq(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllLt(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllGt(arg1, arg2, 0b0111);
}
AZ_MATH_INLINE bool Vec3::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b0111);
}
@@ -485,7 +486,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec3::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0x0FFF);
+ return Sse::CmpAllEq(arg1, arg2, 0b0111);
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl
index 1cf0a35d7f..f3a4feb524 100644
--- a/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Internal/SimdMathVec4_sse.inl
@@ -455,31 +455,32 @@ namespace AZ
AZ_MATH_INLINE bool Vec4::CmpAllEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0xFFFF);
+ // Check the first four bits for Vector4
+ return Sse::CmpAllEq(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllLt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLt(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllLt(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllLtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllLtEq(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllLtEq(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllGt(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGt(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllGt(arg1, arg2, 0b1111);
}
AZ_MATH_INLINE bool Vec4::CmpAllGtEq(FloatArgType arg1, FloatArgType arg2)
{
- return Sse::CmpAllGtEq(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllGtEq(arg1, arg2, 0b1111);
}
@@ -521,7 +522,7 @@ namespace AZ
AZ_MATH_INLINE bool Vec4::CmpAllEq(Int32ArgType arg1, Int32ArgType arg2)
{
- return Sse::CmpAllEq(arg1, arg2, 0xFFFF);
+ return Sse::CmpAllEq(arg1, arg2, 0b1111);
}
diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h
new file mode 100644
index 0000000000..0e7a4ac356
--- /dev/null
+++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+namespace AZ
+{
+ /**
+ * Utility class for reflecting an AZ::Interface through the BehaviorContext
+ *
+ * Example:
+ *
+ * class MyInterface
+ * {
+ * public:
+ * AZ_RTTI(MyInterface, "{BADDF000D-CDCD-CDCD-CDCD-BAAAADF0000D}");
+ * virtual ~MyInterface() = default;
+ *
+ * virtual AZStd::string Foo() = 0;
+ * virtual void Bar(float x, float y) = 0;
+ * };
+ *
+ * class MySystemProxy
+ * : public BehaviorInterfaceProxy
+ * {
+ * public:
+ * AZ_RTTI(MySystemProxy, "{CDCDCDCD-BAAD-BADD-F00D-CDCDCDCDCDCD}", BehaviorInterfaceProxy);
+ * AZ_BEHAVIOR_INTERFACE(MySystemProxy, MyInterface);
+ * };
+ *
+ * void Reflect(AZ::ReflectContext* context)
+ * {
+ * if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context))
+ * {
+ * behaviorContext->ConstantProperty("g_MySystem", MySystemProxy::GetProxy)
+ * ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ * ->Attribute(AZ::Script::Attributes::Module, "MyModule");
+ *
+ * behaviorContext->Class("MySystemInterface")
+ * ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ * ->Attribute(AZ::Script::Attributes::Module, "MyModule")
+ *
+ * ->Method("Foo", MySystemProxy::WrapMethod<&MyInterface::Foo>())
+ * ->Method("Bar", MySystemProxy::WrapMethod<&MyInterface::Bar>());
+ * }
+ * }
+ */
+ template
+ class BehaviorInterfaceProxy
+ {
+ public:
+ AZ_CLASS_ALLOCATOR(BehaviorInterfaceProxy, AZ::SystemAllocator, 0);
+ AZ_RTTI(BehaviorInterfaceProxy, "{E7CC8D27-4499-454E-A7DF-3F72FBECD30D}");
+
+ BehaviorInterfaceProxy() = default;
+ virtual ~BehaviorInterfaceProxy() = default;
+
+ //! Stores the instance which will use the provided shared_ptr deleter when the reference count hits zero
+ BehaviorInterfaceProxy(AZStd::shared_ptr sharedInstance)
+ : m_instance(AZStd::move(sharedInstance))
+ {
+ }
+
+ //! Stores the instance which will perform a no-op deleter when the reference count hits zero
+ BehaviorInterfaceProxy(T* rawIntance)
+ : m_instance(rawIntance, [](T*) {})
+ {
+ }
+
+ //! Returns if the m_instance shared pointer is non-nullptr
+ bool IsValid() const { return m_instance; }
+
+ protected:
+ //! Internal access for use in the derived GetProxy function
+ static T* GetInstance()
+ {
+ T* interfacePtr = AZ::Interface::Get();
+ AZ_Warning("BehaviorInterfaceProxy", interfacePtr,
+ "There is currently no global %s registered with an AZ Interface",
+ AzTypeInfo::Name()
+ );
+ // Don't delete the global instance, it is not owned by the behavior context
+ return interfacePtr;
+ }
+
+ template
+ struct MethodWrapper
+ {
+ template
+ static auto WrapMethod()
+ {
+ using ReturnType = AZStd::function_traits_get_result_t>;
+ return [](Proxy* proxy, Args... params) -> ReturnType
+ {
+ if (proxy && proxy->IsValid())
+ {
+ return AZStd::invoke(Method, proxy->m_instance, AZStd::forward(params)...);
+ }
+ return ReturnType();
+ };
+ }
+ };
+
+ AZStd::shared_ptr m_instance;
+ };
+
+ #define AZ_BEHAVIOR_INTERFACE(ProxyType, InterfaceType) \
+ static ProxyType GetProxy() { return GetInstance(); } \
+ template \
+ static auto WrapMethod() { \
+ using FuncTraits = AZStd::function_traits>; \
+ return FuncTraits::template expand_args::template WrapMethod(); \
+ } \
+ ProxyType() = default; \
+ ProxyType(AZStd::shared_ptr sharedInstance) : BehaviorInterfaceProxy(sharedInstance) {} \
+ ProxyType(InterfaceType* rawIntance) : BehaviorInterfaceProxy(rawIntance) {}
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp
index a83232c8cb..3b2aebdee6 100644
--- a/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -87,6 +88,8 @@ void ScriptSystemComponent::Activate()
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, "lua");
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::AddExtension, "luac");
+ AZ::Data::AssetCatalogRequestBus::Broadcast(
+ &AZ::Data::AssetCatalogRequests::EnableCatalogForAsset, AZ::AzTypeInfo::Uuid());
if (Data::AssetManager::Instance().IsReady())
{
@@ -925,6 +928,7 @@ void ScriptSystemComponent::Reflect(ReflectContext* reflection)
// reflect default entity
MathReflect(behaviorContext);
ScriptDebug::Reflect(behaviorContext);
+ Debug::ProfilerReflect(behaviorContext);
Debug::TraceReflect(behaviorContext);
behaviorContext->Class("Platform")
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
index 4097348798..08cfb11d34 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskExecutor.cpp
@@ -363,7 +363,11 @@ namespace AZ
{
++m_graphsRemaining;
- event->m_executor = this; // Used to validate event is not waited for inside a job
+ if (event)
+ {
+ event->IncWaitCount();
+ event->m_executor = this; // Used to validate event is not waited for inside a job
+ }
// Submit all tasks that have no inbound edges
for (Internal::Task& task : graph.Tasks())
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
index f57b06890a..eeb46d6887 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.cpp
@@ -20,6 +20,46 @@ namespace AZ
m_semaphore.acquire();
}
+ void TaskGraphEvent::IncWaitCount()
+ {
+ // guess zero to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
+ int expectedValue = 0;
+ while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue + 1))
+ {
+ // value will be negative once event is ready to signal or has been signaled. Shouldn't happen.
+ AZ_Assert(expectedValue >= 0, "Called TaskGraphEvent::IncWaitCount on a signalled event");
+ if (expectedValue < 0) // event already signaled, skip
+ {
+ return;
+ }
+ };
+ }
+
+ void TaskGraphEvent::Signal()
+ {
+ // guess one to optimize for single task graph using an event, if multiple are using it then this will take 2+ comp_exch calls
+ int expectedValue = 1;
+ while(!m_waitCount.compare_exchange_weak(expectedValue, expectedValue - 1))
+ {
+ // It's an error for Signal to be called if no one is waiting, or the event has already been signaled
+ AZ_Assert(expectedValue > 0, "Called TaskGraphEvent::Signal when event is either signaled or unused");
+ if (expectedValue < 0) // return if already signaled
+ {
+ return;
+ }
+ };
+
+ if (expectedValue == 1) // This call to Signal decremented the value to 0.
+ {
+ expectedValue = 0;
+ // validate no one incremented the wait count and mark signalling state
+ if (m_waitCount.compare_exchange_strong(expectedValue, -1))
+ {
+ m_semaphore.release();
+ }
+ }
+ }
+
void TaskToken::PrecedesInternal(TaskToken& comesAfter)
{
AZ_Assert(!m_parent.m_submitted, "Cannot mutate a TaskGraph that was previously submitted.");
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
index 9553013a4b..fa6f5dbe94 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.h
@@ -61,14 +61,14 @@ namespace AZ
uint32_t m_index;
};
- // A TaskGraphEvent may be used to block until a task graph has finished executing. Usage
+ // A TaskGraphEvent may be used to block until one or more task graphs has finished executing. Usage
// is NOT recommended for the majority of tasks (prefer to simply containing expanding/contracting
// the graph without synchronization over the course of the frame). However, the event
// is useful for the edges of the computation graph.
//
// You are responsible for ensuring the event object lifetime exceeds the task graph lifetime.
//
- // After the TaskGraphEvent is signaled, you are allowed to reuse the same TaskGraphEvent
+ // After the TaskGraphEvent is signaled, you are NOT allowed to reuse the same TaskGraphEvent
// for a future submission.
class TaskGraphEvent
{
@@ -81,10 +81,12 @@ namespace AZ
friend class TaskGraph;
friend class TaskExecutor;
+ void IncWaitCount();
void Signal();
AZStd::binary_semaphore m_semaphore;
- TaskExecutor* m_executor = nullptr;
+ AZStd::atomic_int m_waitCount = 0;
+ TaskExecutor* m_executor = nullptr;
};
// The TaskGraph encapsulates a set of tasks and their interdependencies. After adding
diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
index 7b2f0cefdc..9a5289eb82 100644
--- a/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
+++ b/Code/Framework/AzCore/AzCore/Task/TaskGraph.inl
@@ -33,11 +33,6 @@ namespace AZ
return m_semaphore.try_acquire_for(AZStd::chrono::milliseconds{ 0 });
}
- inline void TaskGraphEvent::Signal()
- {
- m_semaphore.release();
- }
-
template
TaskToken TaskGraph::AddTask(TaskDescriptor const& desc, Lambda&& lambda)
{
diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake
index 6a9e5a29d6..a5cc3fdcd4 100644
--- a/Code/Framework/AzCore/AzCore/azcore_files.cmake
+++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake
@@ -108,6 +108,8 @@ set(FILES
Debug/Profiler.inl
Debug/Profiler.h
Debug/ProfilerBus.h
+ Debug/ProfilerReflection.cpp
+ Debug/ProfilerReflection.h
Debug/StackTracer.h
Debug/EventTrace.h
Debug/EventTrace.cpp
@@ -456,6 +458,7 @@ set(FILES
RTTI/BehaviorContext.h
RTTI/BehaviorContextUtilities.h
RTTI/BehaviorContextUtilities.cpp
+ RTTI/BehaviorInterfaceProxy.h
RTTI/BehaviorObjectSignals.h
RTTI/TypeSafeIntegral.h
Script/ScriptAsset.cpp
diff --git a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
index 28d3459ba3..4535387902 100644
--- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
+++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
@@ -17,7 +17,7 @@
#include
-namespace AZ
+namespace AZ::Debug
{
#if defined(AZ_ENABLE_DEBUG_TOOLS)
LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo);
@@ -26,94 +26,91 @@ namespace AZ
constexpr int g_maxMessageLength = 4096;
- namespace Debug
+ namespace Platform
{
- namespace Platform
- {
#if defined(AZ_ENABLE_DEBUG_TOOLS)
- bool IsDebuggerPresent()
+ bool IsDebuggerPresent()
+ {
+ return ::IsDebuggerPresent() ? true : false;
+ }
+
+ void HandleExceptions(bool isEnabled)
+ {
+ if (isEnabled)
{
- return ::IsDebuggerPresent() ? true : false;
+ g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler);
}
-
- void HandleExceptions(bool isEnabled)
+ else
{
- if (isEnabled)
- {
- g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler);
- }
- else
- {
- ::SetUnhandledExceptionFilter(g_previousExceptionHandler);
- g_previousExceptionHandler = NULL;
- }
- }
-
- bool AttachDebugger()
- {
- if (IsDebuggerPresent())
- {
- return true;
- }
-
- // Launch vsjitdebugger.exe, this app is always present in System32 folder
- // with an installation of any version of visual studio.
- // It will open a debugging dialog asking the user what debugger to use
-
- STARTUPINFOW startupInfo = {0};
- startupInfo.cb = sizeof(startupInfo);
- PROCESS_INFORMATION processInfo = {0};
-
- wchar_t cmdline[MAX_PATH];
- swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
- bool success = ::CreateProcessW(
- NULL, // No module name (use command line)
- cmdline, // Command line
- NULL, // Process handle not inheritable
- NULL, // Thread handle not inheritable
- FALSE, // No handle inheritance
- 0, // No creation flags
- NULL, // Use parent's environment block
- NULL, // Use parent's starting directory
- &startupInfo, // Pointer to STARTUPINFO structure
- &processInfo); // Pointer to PROCESS_INFORMATION structure
-
- if (success)
- {
- ::WaitForSingleObject(processInfo.hProcess, INFINITE);
- ::CloseHandle(processInfo.hProcess);
- ::CloseHandle(processInfo.hThread);
- return true;
- }
- return false;
- }
-
- void DebugBreak()
- {
- __debugbreak();
- }
-#endif // AZ_ENABLE_DEBUG_TOOLS
-
- void Terminate(int exitCode)
- {
- TerminateProcess(GetCurrentProcess(), exitCode);
- }
-
- void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
- {
- AZStd::fixed_wstring tmpW;
- if(window)
- {
- AZStd::to_wstring(tmpW, window);
- tmpW += L": ";
- OutputDebugStringW(tmpW.c_str());
- tmpW.clear();
- }
- AZStd::to_wstring(tmpW, message);
- OutputDebugStringW(tmpW.c_str());
+ ::SetUnhandledExceptionFilter(g_previousExceptionHandler);
+ g_previousExceptionHandler = NULL;
}
}
- }
+
+ bool AttachDebugger()
+ {
+ if (IsDebuggerPresent())
+ {
+ return true;
+ }
+
+ // Launch vsjitdebugger.exe, this app is always present in System32 folder
+ // with an installation of any version of visual studio.
+ // It will open a debugging dialog asking the user what debugger to use
+
+ STARTUPINFOW startupInfo = {0};
+ startupInfo.cb = sizeof(startupInfo);
+ PROCESS_INFORMATION processInfo = {0};
+
+ wchar_t cmdline[MAX_PATH];
+ swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId());
+ bool success = ::CreateProcessW(
+ NULL, // No module name (use command line)
+ cmdline, // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ FALSE, // No handle inheritance
+ 0, // No creation flags
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &startupInfo, // Pointer to STARTUPINFO structure
+ &processInfo); // Pointer to PROCESS_INFORMATION structure
+
+ if (success)
+ {
+ ::WaitForSingleObject(processInfo.hProcess, INFINITE);
+ ::CloseHandle(processInfo.hProcess);
+ ::CloseHandle(processInfo.hThread);
+ return true;
+ }
+ return false;
+ }
+
+ void DebugBreak()
+ {
+ __debugbreak();
+ }
+#endif // AZ_ENABLE_DEBUG_TOOLS
+
+ void Terminate(int exitCode)
+ {
+ TerminateProcess(GetCurrentProcess(), exitCode);
+ }
+
+ void OutputToDebugger([[maybe_unused]] const char* window, const char* message)
+ {
+ AZStd::fixed_wstring tmpW;
+ if(window)
+ {
+ AZStd::to_wstring(tmpW, window);
+ tmpW += L": ";
+ OutputDebugStringW(tmpW.c_str());
+ tmpW.clear();
+ }
+ AZStd::to_wstring(tmpW, message);
+ OutputDebugStringW(tmpW.c_str());
+ }
+ } // namespace Platform
#if defined(AZ_ENABLE_DEBUG_TOOLS)
@@ -187,6 +184,8 @@ namespace AZ
azsnprintf(message, g_maxMessageLength, "Exception : 0x%lX - '%s' [%p]\n", ExceptionInfo->ExceptionRecord->ExceptionCode, GetExeptionName(ExceptionInfo->ExceptionRecord->ExceptionCode), ExceptionInfo->ExceptionRecord->ExceptionAddress);
Debug::Trace::Instance().Output(nullptr, message);
+ Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
+
EBUS_EVENT(Debug::TraceMessageDrillerBus, OnException, message);
bool result = false;
@@ -198,7 +197,7 @@ namespace AZ
// if someone ever returns TRUE we assume that they somehow handled this exception and continue.
return EXCEPTION_CONTINUE_EXECUTION;
}
- Debug::Trace::Instance().PrintCallstack(nullptr, 0, ExceptionInfo->ContextRecord);
+
Debug::Trace::Instance().Output(nullptr, "==================================================================\n");
// allowing continue of execution is not valid here. This handler gets called for serious exceptions.
@@ -211,4 +210,4 @@ namespace AZ
}
#endif
-}
+} // namspace AZ::Debug
diff --git a/Code/Framework/AzCore/Tests/TaskTests.cpp b/Code/Framework/AzCore/Tests/TaskTests.cpp
index 9e839f60ee..4f53772d51 100644
--- a/Code/Framework/AzCore/Tests/TaskTests.cpp
+++ b/Code/Framework/AzCore/Tests/TaskTests.cpp
@@ -610,15 +610,16 @@ namespace UnitTest
g.Follows(e, f);
g.Precedes(d);
- TaskGraphEvent ev;
- graph.SubmitOnExecutor(*m_executor, &ev);
- ev.Wait();
+ TaskGraphEvent ev1;
+ graph.SubmitOnExecutor(*m_executor, &ev1);
+ ev1.Wait();
EXPECT_EQ(3 | 0b100000, x);
x = 0;
- graph.SubmitOnExecutor(*m_executor, &ev);
- ev.Wait();
+ TaskGraphEvent ev2;
+ graph.SubmitOnExecutor(*m_executor, &ev2);
+ ev2.Wait();
EXPECT_EQ(3 | 0b100000, x);
}
diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
index 8fb986802e..323e834413 100644
--- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp
@@ -204,7 +204,6 @@ namespace AzFramework
systemEntity->Activate();
AZ_Assert(systemEntity->GetState() == AZ::Entity::State::Active, "System Entity failed to activate.");
-
if (m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); m_isStarted)
{
if (m_startupParameters.m_loadAssetCatalog)
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
index cd30b753b5..c1c5775958 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp
@@ -12,6 +12,7 @@
#include
#include
+#include
#include
#include
#include
@@ -363,6 +364,23 @@ namespace AZ::IO
, m_mainThreadId{ AZStd::this_thread::get_id() }
{
CompressionBus::Handler::BusConnect();
+
+ // If the settings registry is not available at this point,
+ // then something catastrophic has happened in the application startup.
+ // That should have been caught and messaged out earlier in startup.
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
+ {
+ // Automatically register the event if it's not registered, because
+ // this system is initialized before the settings registry has loaded the event list.
+ AZ::ComponentApplicationLifecycle::RegisterHandler(
+ *settingsRegistry, m_componentApplicationLifecycleHandler,
+ [this](AZStd::string_view /*path*/, AZ::SettingsRegistryInterface::Type /*type*/)
+ {
+ OnSystemEntityActivated();
+ },
+ "SystemComponentsActivated",
+ /*autoRegisterEvent*/ true);
+ }
}
//////////////////////////////////////////////////////////////////////////
@@ -1175,13 +1193,20 @@ namespace AZ::IO
}
}
- auto bundleManifest = GetBundleManifest(desc.pZip);
AZStd::shared_ptr bundleCatalog;
+ auto bundleManifest = GetBundleManifest(desc.pZip);
if (bundleManifest)
{
bundleCatalog = GetBundleCatalog(desc.pZip, bundleManifest->GetCatalogName());
}
+ // If this archive is loaded before the serialize context is available, then the manifest and catalog will need to be loaded later.
+ if (!bundleManifest || !bundleCatalog)
+ {
+ m_archivesWithCatalogsToLoad.push_back(
+ ArchivesWithCatalogsToLoad(szFullPath, szBindRoot, flags, nextBundle, desc.m_strFileName));
+ }
+
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
@@ -1219,12 +1244,17 @@ namespace AZ::IO
m_levelOpenEvent.Signal(levelDirs);
}
- AZ::IO::ArchiveNotificationBus::Broadcast([](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
- AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle, AZStd::shared_ptr bundleCatalog)
+ if (bundleManifest && bundleCatalog)
{
- archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
- }, desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
-
+ AZ::IO::ArchiveNotificationBus::Broadcast(
+ [](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
+ AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
+ AZStd::shared_ptr bundleCatalog)
+ {
+ archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
+ },
+ desc.m_strFileName.c_str(), bundleManifest, nextBundle, bundleCatalog);
+ }
return true;
}
@@ -2138,7 +2168,7 @@ namespace AZ::IO
}
currentDirPattern = currentDir + AZ_FILESYSTEM_SEPARATOR_WILDCARD;
- currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "levels.pak";
+ currentFilePattern = currentDir + AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING + "level.pak";
ZipDir::FileEntry* fileEntry = findFile.FindExact(currentFilePattern.c_str());
if (fileEntry)
@@ -2175,4 +2205,36 @@ namespace AZ::IO
return catalogInfo;
}
+
+ void Archive::OnSystemEntityActivated()
+ {
+ for (const auto& archiveInfo : m_archivesWithCatalogsToLoad)
+ {
+ AZStd::intrusive_ptr archive =
+ OpenArchive(archiveInfo.m_fullPath, archiveInfo.m_bindRoot, archiveInfo.m_flags, nullptr);
+ if (!archive)
+ {
+ continue;
+ }
+
+ ZipDir::CachePtr pZip = static_cast(archive.get())->GetCache();
+
+ AZStd::shared_ptr bundleCatalog;
+ auto bundleManifest = GetBundleManifest(pZip);
+ if (bundleManifest)
+ {
+ bundleCatalog = GetBundleCatalog(pZip, bundleManifest->GetCatalogName());
+ }
+
+ AZ::IO::ArchiveNotificationBus::Broadcast(
+ [](AZ::IO::ArchiveNotifications* archiveNotifications, const char* bundleName,
+ AZStd::shared_ptr bundleManifest, const AZ::IO::FixedMaxPath& nextBundle,
+ AZStd::shared_ptr bundleCatalog)
+ {
+ archiveNotifications->BundleOpened(bundleName, bundleManifest, nextBundle.c_str(), bundleCatalog);
+ },
+ archiveInfo.m_strFileName.c_str(), bundleManifest, archiveInfo.m_nextBundle, bundleCatalog);
+ }
+ m_archivesWithCatalogsToLoad.clear();
+ }
}
diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
index f08d90a66e..279702b433 100644
--- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
+++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.h
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -271,6 +272,11 @@ namespace AZ::IO
ZipDir::CachePtr* pZip = {}) const;
private:
+ // Archives can't be fully mounted until the system entity has been activated,
+ // because mounting them requires the BundlingSystemComponent and the serialization system
+ // to both be available.
+ void OnSystemEntityActivated();
+
bool OpenPackCommon(AZStd::string_view szBindRoot, AZStd::string_view pName, AZStd::intrusive_ptr pData = nullptr, bool addLevels = true);
bool OpenPacksCommon(AZStd::string_view szDir, AZStd::string_view pWildcardIn, AZStd::vector* pFullPaths = nullptr, bool addLevels = true);
@@ -313,6 +319,8 @@ namespace AZ::IO
mutable AZStd::shared_mutex m_csZips;
ZipArray m_arrZips;
+ AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
+
//////////////////////////////////////////////////////////////////////////
// Opened files collector.
//////////////////////////////////////////////////////////////////////////
@@ -339,5 +347,34 @@ namespace AZ::IO
// [LYN-2376] Remove once legacy slice support is removed
LevelPackOpenEvent m_levelOpenEvent;
LevelPackCloseEvent m_levelCloseEvent;
+
+ // If pak files are loaded before the serialization and bundling system
+ // are ready to go, their asset catalogs can't be loaded.
+ // In this case, cache information about those archives,
+ // and attempt to load the catalogs later, when the required systems are enabled.
+ struct ArchivesWithCatalogsToLoad
+ {
+ ArchivesWithCatalogsToLoad(
+ AZStd::string_view fullPath,
+ AZStd::string_view bindRoot,
+ int flags,
+ AZ::IO::PathView nextBundle,
+ AZ::IO::Path strFileName)
+ : m_fullPath(fullPath)
+ , m_bindRoot(bindRoot)
+ , m_flags(flags)
+ , m_nextBundle(nextBundle)
+ , m_strFileName(strFileName)
+ {
+ }
+
+ AZ::IO::Path m_strFileName;
+ AZStd::string m_fullPath;
+ AZStd::string m_bindRoot;
+ AZ::IO::PathView m_nextBundle;
+ int m_flags;
+ };
+
+ AZStd::vector m_archivesWithCatalogsToLoad;
};
}
diff --git a/Code/Framework/AzFramework/AzFramework/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/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/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h
index be93e1af1a..33b60f0f51 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ViewPaneOptions.h
@@ -40,7 +40,7 @@ namespace AzToolsFramework
bool isDisabledInSimMode = false; ///< set to true if the view pane should not be openable from level editor menu when editor is in simulation mode.
bool showOnToolsToolbar = false; ///< set to true if the view pane should create a button on the tools toolbar to open/close the pane
- QString toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
+ AZStd::string toolbarIcon; ///< path to the icon to use for the toolbar button - only used if showOnToolsToolbar is set to true
};
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
index 67563aaf69..f203251407 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp
@@ -426,6 +426,8 @@ namespace AzToolsFramework
->Property("showInMenu", BehaviorValueProperty(&ViewPaneOptions::showInMenu))
->Property("canHaveMultipleInstances", BehaviorValueProperty(&ViewPaneOptions::canHaveMultipleInstances))
->Property("isPreview", BehaviorValueProperty(&ViewPaneOptions::isPreview))
+ ->Property("showOnToolsToolbar", BehaviorValueProperty(&ViewPaneOptions::showOnToolsToolbar))
+ ->Property("toolbarIcon", BehaviorValueProperty(&ViewPaneOptions::toolbarIcon))
;
behaviorContext->EBus("EditorRequestBus")
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
index 483faf03c2..7da6f794d6 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp
@@ -102,7 +102,7 @@ namespace AzToolsFramework
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AssetSystemBus::Handler::BusDisconnect();
- m_assetBrowserModel.release();
+ m_assetBrowserModel.reset();
EntryCache::DestroyInstance();
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
index 61b257a189..0a27a5cb90 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
@@ -26,8 +26,12 @@ namespace AzToolsFramework
AZ::Interface::Unregister(this);
}
- void ContainerEntitySystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
+ void ContainerEntitySystemComponent::Reflect(AZ::ReflectContext* context)
{
+ if (auto serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()->Version(1);
+ }
}
void ContainerEntitySystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
index 44ff603c0c..16640f4edf 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
@@ -47,8 +47,12 @@ namespace AzToolsFramework
AZ::Interface::Unregister(this);
}
- void FocusModeSystemComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context)
+ void FocusModeSystemComponent::Reflect(AZ::ReflectContext* context)
{
+ if (auto serializeContext = azrtti_cast(context))
+ {
+ serializeContext->Class()->Version(1);
+ }
}
void FocusModeSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp
index 574470ad6e..7ee20997f9 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.cpp
@@ -210,8 +210,8 @@ namespace AzToolsFramework
m_enabled = enabled;
if (!enabled)
{
- // Send an internal focus change event to reset our input state to fresh if we're disabled.
- HandleFocusChange(nullptr);
+ // Clear input channels to reset our input state if we're disabled.
+ ClearInputChannels(nullptr);
}
}
@@ -246,7 +246,7 @@ namespace AzToolsFramework
if (eventType == QEvent::Type::MouseMove)
{
- // clear override cursor when moving outside of the viewport
+ // Clear override cursor when moving outside of the viewport
const auto* mouseEvent = static_cast(event);
if (m_overrideCursor && !m_sourceWidget->geometry().contains(m_sourceWidget->mapFromGlobal(mouseEvent->globalPos())))
{
@@ -255,6 +255,13 @@ namespace AzToolsFramework
}
}
+ // If the application state changes (e.g. we have alt-tabbed or minimized the
+ // main editor window) then ensure all input channels are cleared
+ if (eventType == QEvent::ApplicationStateChange)
+ {
+ ClearInputChannels(event);
+ }
+
// Only accept mouse & key release events that originate from an object that is not our target widget,
// as we don't want to erroneously intercept user input meant for another component.
if (object != m_sourceWidget && eventType != QEvent::Type::KeyRelease && eventType != QEvent::Type::MouseButtonRelease)
@@ -264,9 +271,6 @@ namespace AzToolsFramework
if (eventType == QEvent::FocusIn || eventType == QEvent::FocusOut)
{
- // If our focus changes, go ahead and reset all input devices.
- HandleFocusChange(event);
-
// If we focus in on the source widget and the mouse is contained in its
// bounds, refresh the cached cursor position to ensure it is up to date (this
// ensures cursor positions are refreshed correctly with context menu focus changes)
@@ -451,7 +455,7 @@ namespace AzToolsFramework
NotifyUpdateChannelIfNotIdle(cursorZChannel, wheelEvent);
}
- void QtEventToAzInputMapper::HandleFocusChange(QEvent* event)
+ void QtEventToAzInputMapper::ClearInputChannels(QEvent* event)
{
for (auto& channelData : m_channels)
{
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h
index 4cb391e63b..4c4e09ea05 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputManager.h
@@ -138,8 +138,9 @@ namespace AzToolsFramework
void HandleKeyEvent(QKeyEvent* keyEvent);
// Handles mouse wheel events.
void HandleWheelEvent(QWheelEvent* wheelEvent);
- // Handles focus change events.
- void HandleFocusChange(QEvent* event);
+
+ // Clear all input channels (set all channel states to 'ended').
+ void ClearInputChannels(QEvent* event);
// Populates m_keyMappings.
void InitializeKeyMappings();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
index a6a80e58d3..7c5a6ebb8a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp
@@ -12,11 +12,12 @@
#include
#include
+#include
#include
#include
#include
-#include
#include
+#include
#include
#include
#include
@@ -565,6 +566,7 @@ namespace AzToolsFramework
parentId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId);
}
+ // If the parent entity isn't owned by a prefab instance, bail.
InstanceOptionalReference owningInstanceOfParentEntity = GetOwnerInstanceByEntityId(parentId);
if (!owningInstanceOfParentEntity)
{
@@ -572,6 +574,14 @@ namespace AzToolsFramework
"Cannot add entity because the owning instance of parent entity with id '%llu' could not be found.",
static_cast(parentId)));
}
+
+ // If the parent entity is a closed container, bail.
+ if (auto containerEntityInterface = AZ::Interface::Get(); !containerEntityInterface->IsContainerOpen(parentId))
+ {
+ return AZ::Failure(AZStd::string::format(
+ "Cannot add entity because the parent entity (id '%llu') is a closed container entity.",
+ static_cast(parentId)));
+ }
EntityAlias entityAlias = Instance::GenerateEntityAlias();
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp
index a88711a9ed..277d3fa3c5 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp
@@ -129,7 +129,7 @@ namespace AzToolsFramework
ToastId ToastNotificationsView::CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration)
{
- AzQtComponents::ToastNotification* notification = aznew AzQtComponents::ToastNotification(parentWidget(), toastConfiguration);
+ AzQtComponents::ToastNotification* notification = new AzQtComponents::ToastNotification(this, toastConfiguration);
ToastId toastId = AZ::Entity::MakeId();
m_notifications[toastId] = notification;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
index 434a1d8303..13ec27c1b8 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
@@ -43,6 +43,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -764,10 +765,21 @@ namespace AzToolsFramework
return canHandleData;
}
- bool EntityOutlinerListModel::CanDropMimeDataAssets(const QMimeData* data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex& /*parent*/) const
+ bool EntityOutlinerListModel::CanDropMimeDataAssets(
+ const QMimeData* data,
+ [[maybe_unused]] Qt::DropAction action,
+ [[maybe_unused]] int row,
+ [[maybe_unused]] int column,
+ const QModelIndex& parent) const
{
- using namespace AzToolsFramework;
-
+ // Disable dropping assets on closed container entities.
+ AZ::EntityId parentId = GetEntityFromIndex(parent);
+ if (auto containerEntityInterface = AZ::Interface::Get();
+ !containerEntityInterface->IsContainerOpen(parentId))
+ {
+ return false;
+ }
+
if (data->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType()))
{
return DecodeAssetMimeData(data);
@@ -788,8 +800,15 @@ namespace AzToolsFramework
return false;
}
+ // If the parent entity is a closed container, bail.
+ if (auto containerEntityInterface = AZ::Interface::Get();
+ !containerEntityInterface->IsContainerOpen(assignParentId))
+ {
+ return false;
+ }
+
// Source Files
- if (sourceFiles.size() > 0)
+ if (!sourceFiles.empty())
{
// Get position (center of viewport). If no viewport is available, (0,0,0) will be used.
AZ::Vector3 viewportCenterPosition = AZ::Vector3::CreateZero();
@@ -973,6 +992,12 @@ namespace AzToolsFramework
return false;
}
+ // If the new parent is a closed container, bail.
+ if (auto containerEntityInterface = AZ::Interface::Get(); !containerEntityInterface->IsContainerOpen(newParentId))
+ {
+ return false;
+ }
+
// Ignore entities not owned by the editor context. It is assumed that all entities belong
// to the same context since multiple selection doesn't span across views.
for (const AZ::EntityId& entityId : selectedEntityIds)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/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/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/System.h b/Code/Legacy/CrySystem/System.h
index 015b09a69b..a3a0f12278 100644
--- a/Code/Legacy/CrySystem/System.h
+++ b/Code/Legacy/CrySystem/System.h
@@ -590,7 +590,7 @@ public:
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..ac0683cf1b 100644
--- a/Code/Legacy/CrySystem/SystemInit.cpp
+++ b/Code/Legacy/CrySystem/SystemInit.cpp
@@ -649,7 +649,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");
@@ -786,29 +786,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 +806,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 +815,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 +1319,7 @@ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////
// Open basic pak files after intro movie playback started
//////////////////////////////////////////////////////////////////////////
- OpenBasicPaks();
+ OpenPlatformPaks();
//////////////////////////////////////////////////////////////////////////
// AUDIO
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();
@@ -60,8 +60,8 @@ namespace AssetProcessor
AssetUtilities::ResetAssetRoot();
m_application.reset();
- delete m_errorAbsorber;
- m_errorAbsorber = nullptr;
+ m_errorAbsorber.reset();
+
if (m_ownsSysAllocator)
{
AZ::AllocatorInstance::Destroy();
diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
index 0b02b168dc..5bcb6dc583 100644
--- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
+++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp
@@ -241,8 +241,10 @@ void AssetProcessorManagerTest::SetUp()
ASSERT_TRUE(m_mockApplicationManager->RegisterAssetRecognizerAsBuilder(rec));
m_mockApplicationManager->BusConnect();
+ AZ_Printf("UnitTest", "Allocating APM\n")
m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get()));
- m_assertAbsorber.Clear();
+ AZ_Printf("UnitTest", "APM ready\n");
+ m_errorAbsorber->Clear();
m_isIdling = false;
@@ -333,9 +335,9 @@ TEST_F(AssetProcessorManagerTest, UnitTestForGettingJobInfoBySourceUUIDSuccess)
EXPECT_STRCASEEQ(relFileName.toUtf8().data(), response.m_jobList[0].m_sourceFile.c_str());
EXPECT_STRCASEEQ(tempPath.filePath("subfolder1").toUtf8().data(), response.m_jobList[0].m_watchFolder.c_str());
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToDatabase)
@@ -387,9 +389,9 @@ TEST_F(AssetProcessorManagerTest, WarningsAndErrorsReported_SuccessfullySavedToD
ASSERT_EQ(response.m_jobList[0].m_warningCount, 11);
ASSERT_EQ(response.m_jobList[0].m_errorCount, 22);
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
}
@@ -1311,8 +1313,8 @@ void PathDependencyTest::SetUp()
void PathDependencyTest::TearDown()
{
- ASSERT_EQ(m_assertAbsorber.m_numAssertsAbsorbed, 0);
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numAssertsAbsorbed, 0);
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 0);
AssetProcessorManagerTest::TearDown();
}
@@ -1616,7 +1618,7 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
mainFile.m_products.push_back(productAssetId);
// tell the APM that the asset has been processed and allow it to bubble through its event queue:
- m_assertAbsorber.Clear();
+ m_errorAbsorber->Clear();
m_assetProcessorManager->AssetProcessed(jobDetails.m_jobEntry, processJobResponse);
ASSERT_TRUE(BlockUntilIdle(5000));
@@ -1626,8 +1628,8 @@ TEST_F(PathDependencyTest, AssetProcessed_Impl_SelfReferrentialProductDependency
ASSERT_TRUE(dependencyContainer.empty());
// We are testing 2 different dependencies, so we should get 2 warnings
- ASSERT_EQ(m_assertAbsorber.m_numWarningsAbsorbed, 2);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numWarningsAbsorbed, 2);
+ m_errorAbsorber->Clear();
}
// This test shows the process of deferring resolution of a path dependency works.
@@ -1944,8 +1946,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludePathsExisting_ResolveCorr
);
// Test asset PrimaryFile1 has 4 conflict dependencies
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 4);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 4);
+ m_errorAbsorber->Clear();
}
TEST_F(PathDependencyTest, WildcardDependencies_Deferred_ResolveCorrectly)
@@ -2092,8 +2094,8 @@ TEST_F(PathDependencyTest, WildcardDependencies_ExcludedPathDeferred_ResolveCorr
// Test asset PrimaryFile1 has 4 conflict dependencies
// After test assets dep2 and dep3 are processed,
// another 2 errors will be raised because of the confliction
- ASSERT_EQ(m_assertAbsorber.m_numErrorsAbsorbed, 6);
- m_assertAbsorber.Clear();
+ ASSERT_EQ(m_errorAbsorber->m_numErrorsAbsorbed, 6);
+ m_errorAbsorber->Clear();
}
void PathDependencyTest::RunWildcardTest(bool useCorrectDatabaseSeparator, AssetBuilderSDK::ProductPathDependencyType pathDependencyType, bool buildDependenciesFirst)
@@ -4447,9 +4449,9 @@ AssetBuilderSDK::AssetBuilderDesc MockBuilderInfoHandler::CreateBuilderDesc(cons
void FingerprintTest::SetUp()
{
- AZ_Printf("FingerprintTest", "SetUp start");
+ AZ_Printf("FingerprintTest", "SetUp start\n");
AssetProcessorManagerTest::SetUp();
- AZ_Printf("FingerprintTest", "SetUp self");
+ AZ_Printf("FingerprintTest", "SetUp self\n");
// We don't want the mock application manager to provide builder descriptors, mockBuilderInfoHandler will provide our own
m_mockApplicationManager->BusDisconnect();
@@ -4468,23 +4470,23 @@ void FingerprintTest::SetUp()
});
ASSERT_TRUE(UnitTestUtils::CreateDummyFile(m_absolutePath, ""));
- AZ_Printf("FingerprintTest", "SetUp end");
+ AZ_Printf("FingerprintTest", "SetUp end\n");
}
void FingerprintTest::TearDown()
{
- AZ_Printf("FingerprintTest", "TearDown start");
+ AZ_Printf("FingerprintTest", "TearDown start\n");
m_jobResults = AZStd::vector{};
m_mockBuilderInfoHandler = {};
- AZ_Printf("FingerprintTest", "TearDown parent");
+ AZ_Printf("FingerprintTest", "TearDown parent\n");
AssetProcessorManagerTest::TearDown();
- AZ_Printf("FingerprintTest", "TearDown end");
+ AZ_Printf("FingerprintTest", "TearDown end\n");
}
void FingerprintTest::RunFingerprintTest(QString builderFingerprint, QString jobFingerprint, bool expectedResult)
{
- AZ_Printf("FingerprintTest", "Fingerprint Test Start");
+ AZ_Printf("FingerprintTest", "Fingerprint Test Start\n");
m_mockBuilderInfoHandler.m_builderDesc.m_analysisFingerprint = builderFingerprint.toUtf8().data();
m_mockBuilderInfoHandler.m_jobFingerprint = jobFingerprint;
QMetaObject::invokeMethod(m_assetProcessorManager.get(), "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, m_absolutePath));
@@ -4493,7 +4495,7 @@ void FingerprintTest::RunFingerprintTest(QString builderFingerprint, QString job
ASSERT_EQ(m_mockBuilderInfoHandler.m_createJobsCount, 1);
ASSERT_EQ(m_jobResults.size(), 1);
ASSERT_EQ(m_jobResults[0].m_autoFail, expectedResult);
- AZ_Printf("FingerprintTest", "Fingerprint Test End");
+ AZ_Printf("FingerprintTest", "Fingerprint Test End\n");
}
TEST_F(FingerprintTest, FingerprintChecking_JobFingerprint_NoBuilderFingerprint)
@@ -5318,6 +5320,18 @@ TEST_F(MetadataFileTest, MetadataFile_SourceFileExtensionDifferentCase)
ASSERT_EQ(jobDetails.m_jobEntry.m_pathRelativeToWatchFolder, relFileName);
}
+AZStd::vector QStringListToVector(const QStringList& qstringList)
+{
+ AZStd::vector azVector;
+ // Convert to a vector of AZStd::strings because GTest handles this type better when displaying errors
+ for (const QString& resolvedPath : qstringList)
+ {
+ azVector.emplace_back(resolvedPath.toUtf8().constData());
+ }
+
+ return azVector;
+}
+
bool WildcardSourceDependencyTest::Test(
const AZStd::string& dependencyPath, AZStd::vector& resolvedPaths)
{
@@ -5326,15 +5340,18 @@ bool WildcardSourceDependencyTest::Test(
AssetBuilderSDK::SourceFileDependency dependency(dependencyPath, AZ::Uuid::CreateNull(), AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Wildcards);
bool result = m_assetProcessorManager->ResolveSourceFileDependencyPath(dependency, resolvedName, stringlistPaths);
- // Convert to a vector of AZStd::strings because GTest handles this type better when displaying errors
- for (const QString& resolvedPath : stringlistPaths)
- {
- resolvedPaths.emplace_back(resolvedPath.toUtf8().constData());
- }
+ resolvedPaths = QStringListToVector(stringlistPaths);
return result;
}
+AZStd::vector WildcardSourceDependencyTest::FileAddedTest(const QString& path)
+{
+ auto result = m_assetProcessorManager->GetSourceFilesWhichDependOnSourceFile(path);
+
+ return QStringListToVector(result);
+}
+
void WildcardSourceDependencyTest::SetUp()
{
AssetProcessorManagerTest::SetUp();
@@ -5357,6 +5374,42 @@ void WildcardSourceDependencyTest::SetUp()
// Add a file in the non-recursive scanfolder. Since its not directly in the scan folder, it should always be ignored
UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("no_recurse/one/two/three/f.foo"));
+
+ AzToolsFramework::AssetDatabase::SourceFileDependencyEntryContainer dependencies;
+
+ // Relative path wildcard dependency
+ dependencies.push_back(AzToolsFramework::AssetDatabase::SourceFileDependencyEntry(
+ AZ::Uuid::CreateRandom(), "a.foo", "%a.foo",
+ AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceLikeMatch, 0));
+
+ // Absolute path wildcard dependency
+ dependencies.push_back(AzToolsFramework::AssetDatabase::SourceFileDependencyEntry(
+ AZ::Uuid::CreateRandom(), "b.foo", tempPath.absoluteFilePath("%b.foo").toUtf8().constData(),
+ AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceLikeMatch, 0));
+
+ // Test what happens when we have 2 dependencies on the same file
+ dependencies.push_back(AzToolsFramework::AssetDatabase::SourceFileDependencyEntry(
+ AZ::Uuid::CreateRandom(), "folder/one/d.foo", "%c.foo",
+ AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceLikeMatch, 0));
+
+ dependencies.push_back(AzToolsFramework::AssetDatabase::SourceFileDependencyEntry(
+ AZ::Uuid::CreateRandom(), "folder/one/d.foo", tempPath.absoluteFilePath("%c.foo").toUtf8().constData(),
+ AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceLikeMatch, 0));
+
+#ifdef AZ_PLATFORM_WINDOWS
+ // Test to make sure a relative wildcard dependency doesn't match an absolute path
+ // For example, if the input is C:/project/subfolder1/a.foo
+ // This should not match a wildcard of c%.foo
+ // Take the first character of the tempPath and append %.foo onto it for this test, which should produce something like c%.foo
+ // This only applies to windows because on other OSes if the dependency starts with /, then its an abs path dependency
+ auto test = (tempPath.absolutePath().left(1) + "%.foo");
+ dependencies.push_back(AzToolsFramework::AssetDatabase::SourceFileDependencyEntry(
+ AZ::Uuid::CreateRandom(), "folder/one/d.foo",
+ (test).toUtf8().constData(),
+ AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_SourceLikeMatch, 0));
+#endif
+
+ ASSERT_TRUE(m_assetProcessorManager->m_stateData->SetSourceFileDependencies(dependencies));
}
TEST_F(WildcardSourceDependencyTest, Relative_Broad)
@@ -5455,3 +5508,30 @@ TEST_F(WildcardSourceDependencyTest, Absolute_NoWildcard)
ASSERT_FALSE(Test(tempPath.absoluteFilePath("subfolder1/1a.foo").toUtf8().constData(), resolvedPaths));
ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre());
}
+
+TEST_F(WildcardSourceDependencyTest, NewFile_MatchesSavedRelativeDependency)
+{
+ QDir tempPath(m_tempDir.path());
+
+ auto matches = FileAddedTest(tempPath.absoluteFilePath("subfolder1/1a.foo"));
+
+ ASSERT_THAT(matches, ::testing::UnorderedElementsAre(tempPath.absoluteFilePath("subfolder2/redirected/a.foo").toUtf8().constData()));
+}
+
+TEST_F(WildcardSourceDependencyTest, NewFile_MatchesSavedAbsoluteDependency)
+{
+ QDir tempPath(m_tempDir.path());
+
+ auto matches = FileAddedTest(tempPath.absoluteFilePath("subfolder1/1b.foo"));
+
+ ASSERT_THAT(matches, ::testing::UnorderedElementsAre(tempPath.absoluteFilePath("subfolder2/redirected/b.foo").toUtf8().constData()));
+}
+
+TEST_F(WildcardSourceDependencyTest, NewFile_MatchesDuplicatedDependenciesOnce)
+{
+ QDir tempPath(m_tempDir.path());
+
+ auto matches = FileAddedTest(tempPath.absoluteFilePath("subfolder2/redirected/folder/one/c.foo"));
+
+ ASSERT_THAT(matches, ::testing::UnorderedElementsAre(tempPath.absoluteFilePath("subfolder2/redirected/folder/one/d.foo").toUtf8().constData()));
+}
diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h
index 94cc997938..7bbef41f44 100644
--- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h
+++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h
@@ -58,7 +58,6 @@ protected:
AZStd::unique_ptr m_assetProcessorManager;
AZStd::unique_ptr m_mockApplicationManager;
AZStd::unique_ptr m_config;
- UnitTestUtils::AssertAbsorber m_assertAbsorber; // absorb asserts/warnings/errors so that the unit test output is not cluttered
QString m_gameName;
QDir m_normalizedCacheRootDir;
AZStd::atomic_bool m_isIdling;
@@ -135,6 +134,7 @@ struct WildcardSourceDependencyTest
: AssetProcessorManagerTest
{
bool Test(const AZStd::string& dependencyPath, AZStd::vector& resolvedPaths);
+ AZStd::vector FileAddedTest(const QString& path);
void SetUp() override;
};
diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
index 65e01803aa..51e1163713 100644
--- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
+++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp
@@ -240,7 +240,7 @@ namespace O3DE::ProjectManager
PythonBindingsInterface::Get()->AddProject(projectInfo.m_path);
#ifdef TEMPLATE_GEM_CONFIGURATION_ENABLED
- const GemCatalogScreen::EnableDisableGemsResult gemResult = m_gemCatalogScreen->EnableDisableGemsForProject(m_projectInfo.m_path);
+ const GemCatalogScreen::EnableDisableGemsResult gemResult = m_gemCatalogScreen->EnableDisableGemsForProject(projectInfo.m_path);
if (gemResult == GemCatalogScreen::EnableDisableGemsResult::Failed)
{
QMessageBox::critical(this, tr("Failed to configure gems"), tr("Failed to configure gems for template."));
diff --git a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h
index 40ddb14b83..58f4758edd 100644
--- a/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h
+++ b/Code/Tools/ProjectManager/Source/CreateProjectCtrl.h
@@ -62,9 +62,6 @@ namespace O3DE::ProjectManager
QPushButton* m_secondaryButton = nullptr;
#endif // TEMPLATE_GEM_CONFIGURATION_ENABLED
- QString m_projectTemplatePath;
- ProjectInfo m_projectInfo;
-
NewProjectSettingsScreen* m_newProjectSettingsScreen = nullptr;
GemCatalogScreen* m_gemCatalogScreen = nullptr;
};
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
index 576a4aff6e..fdfcf02155 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
@@ -39,7 +39,6 @@ namespace O3DE::ProjectManager
QRect fullRect, itemRect, contentRect;
CalcRects(options, fullRect, itemRect, contentRect);
- QRect buttonRect = CalcButtonRect(contentRect);
QFont standardFont(options.font);
standardFont.setPixelSize(static_cast(s_fontSize));
@@ -70,15 +69,12 @@ namespace O3DE::ProjectManager
painter->restore();
}
- // Repo enabled
- DrawButton(painter, buttonRect, modelIndex);
-
// Repo name
QString repoName = GemRepoModel::GetName(modelIndex);
repoName = QFontMetrics(standardFont).elidedText(repoName, Qt::TextElideMode::ElideRight, s_nameMaxWidth);
QRect repoNameRect = GetTextRect(standardFont, repoName, s_fontSize);
- int currentHorizontalOffset = buttonRect.left() + s_buttonWidth + s_buttonSpacing;
+ int currentHorizontalOffset = contentRect.left();
repoNameRect.moveTo(currentHorizontalOffset, contentRect.center().y() - repoNameRect.height() / 2);
repoNameRect = painter->boundingRect(repoNameRect, Qt::TextSingleLine, repoName);
@@ -126,7 +122,7 @@ namespace O3DE::ProjectManager
initStyleOption(&options, modelIndex);
int marginsHorizontal = s_itemMargins.left() + s_itemMargins.right() + s_contentMargins.left() + s_contentMargins.right();
- return QSize(marginsHorizontal + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 3, s_height);
+ return QSize(marginsHorizontal + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 3, s_height);
}
bool GemRepoItemDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex)
@@ -139,13 +135,8 @@ namespace O3DE::ProjectManager
if (event->type() == QEvent::KeyPress)
{
auto keyEvent = static_cast(event);
- if (keyEvent->key() == Qt::Key_Space)
- {
- const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
- GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
- return true;
- }
- else if (keyEvent->key() == Qt::Key_X)
+
+ if (keyEvent->key() == Qt::Key_X)
{
emit RemoveRepo(modelIndex);
return true;
@@ -163,17 +154,10 @@ namespace O3DE::ProjectManager
QRect fullRect, itemRect, contentRect;
CalcRects(option, fullRect, itemRect, contentRect);
- const QRect buttonRect = CalcButtonRect(contentRect);
const QRect deleteButtonRect = CalcDeleteButtonRect(contentRect);
- const QRect refreshButtonRect = CalcRefreshButtonRect(contentRect, buttonRect);
+ const QRect refreshButtonRect = CalcRefreshButtonRect(contentRect);
- if (buttonRect.contains(mouseEvent->pos()))
- {
- const bool isAdded = GemRepoModel::IsEnabled(modelIndex);
- GemRepoModel::SetEnabled(*model, modelIndex, !isAdded);
- return true;
- }
- else if (deleteButtonRect.contains(mouseEvent->pos()))
+ if (deleteButtonRect.contains(mouseEvent->pos()))
{
emit RemoveRepo(modelIndex);
return true;
@@ -201,50 +185,15 @@ namespace O3DE::ProjectManager
return QFontMetrics(font).boundingRect(text);
}
- QRect GemRepoItemDelegate::CalcButtonRect(const QRect& contentRect) const
- {
- const QPoint topLeft = QPoint(contentRect.left(), contentRect.top() + contentRect.height() / 2 - s_buttonHeight / 2);
- const QSize size = QSize(s_buttonWidth, s_buttonHeight);
- return QRect(topLeft, size);
- }
-
- void GemRepoItemDelegate::DrawButton(QPainter* painter, const QRect& buttonRect, const QModelIndex& modelIndex) const
- {
- painter->save();
- QPoint circleCenter;
-
- const bool isEnabled = GemRepoModel::IsEnabled(modelIndex);
- if (isEnabled)
- {
- painter->setBrush(m_buttonEnabledColor);
- painter->setPen(m_buttonEnabledColor);
-
- circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1);
- }
- else
- {
- circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius + 1, 1);
- }
-
- // Rounded rect
- painter->drawRoundedRect(buttonRect, s_buttonBorderRadius, s_buttonBorderRadius);
-
- // Circle
- painter->setBrush(m_textColor);
- painter->drawEllipse(circleCenter, s_buttonCircleRadius, s_buttonCircleRadius);
-
- painter->restore();
- }
-
QRect GemRepoItemDelegate::CalcDeleteButtonRect(const QRect& contentRect) const
{
const QPoint topLeft = QPoint(contentRect.right() - s_iconSize, contentRect.center().y() - s_iconSize / 2);
return QRect(topLeft, QSize(s_iconSize, s_iconSize));
}
- QRect GemRepoItemDelegate::CalcRefreshButtonRect(const QRect& contentRect, const QRect& buttonRect) const
+ QRect GemRepoItemDelegate::CalcRefreshButtonRect(const QRect& contentRect) const
{
- const int topLeftX = buttonRect.left() + s_buttonWidth + s_buttonSpacing + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 2 + s_refreshIconSpacing;
+ const int topLeftX = contentRect.left() + s_nameMaxWidth + s_creatorMaxWidth + s_updatedMaxWidth + s_contentSpacing * 2 + s_refreshIconSpacing;
const QPoint topLeft = QPoint(topLeftX, contentRect.center().y() - s_refreshIconSize / 3);
return QRect(topLeft, QSize(s_refreshIconSize, s_refreshIconSize));
}
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
index 69f2eb582d..69d943001d 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.h
@@ -36,7 +36,6 @@ namespace O3DE::ProjectManager
const QColor m_backgroundColor = QColor("#333333"); // Outside of the actual repo item
const QColor m_itemBackgroundColor = QColor("#404040"); // Background color of the repo item
const QColor m_borderColor = QColor("#1E70EB");
- const QColor m_buttonEnabledColor = QColor("#1E70EB");
// Item
inline constexpr static int s_height = 72; // Repo item total height
@@ -53,13 +52,6 @@ namespace O3DE::ProjectManager
inline constexpr static int s_creatorMaxWidth = 115;
inline constexpr static int s_updatedMaxWidth = 125;
- // Button
- inline constexpr static int s_buttonWidth = 32;
- inline constexpr static int s_buttonHeight = 16;
- inline constexpr static int s_buttonBorderRadius = 8;
- inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2;
- inline constexpr static int s_buttonSpacing = 20;
-
// Icon
inline constexpr static int s_iconSize = 24;
inline constexpr static int s_iconSpacing = 16;
@@ -75,8 +67,7 @@ namespace O3DE::ProjectManager
QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const;
QRect CalcButtonRect(const QRect& contentRect) const;
QRect CalcDeleteButtonRect(const QRect& contentRect) const;
- QRect CalcRefreshButtonRect(const QRect& contentRect, const QRect& buttonRect) const;
- void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const;
+ QRect CalcRefreshButtonRect(const QRect& contentRect) const;
void DrawEditButtons(QPainter* painter, const QRect& contentRect) const;
QAbstractItemModel* m_model = nullptr;
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
index 490b509474..0ddfe41434 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
@@ -289,23 +289,22 @@ namespace O3DE::ProjectManager
m_gemRepoHeaderTable->setObjectName("gemRepoHeaderTable");
m_gemRepoListHeader = m_gemRepoHeaderTable->horizontalHeader();
m_gemRepoListHeader->setObjectName("gemRepoListHeader");
+ m_gemRepoListHeader->setDefaultAlignment(Qt::AlignLeft);
m_gemRepoListHeader->setSectionResizeMode(QHeaderView::ResizeMode::Fixed);
// Insert columns so the header labels will show up
m_gemRepoHeaderTable->insertColumn(0);
m_gemRepoHeaderTable->insertColumn(1);
m_gemRepoHeaderTable->insertColumn(2);
- m_gemRepoHeaderTable->insertColumn(3);
- m_gemRepoHeaderTable->setHorizontalHeaderLabels({ tr("Enabled"), tr("Repository Name"), tr("Creator"), tr("Updated") });
+ m_gemRepoHeaderTable->setHorizontalHeaderLabels({ tr("Repository Name"), tr("Creator"), tr("Updated") });
- const int headerExtraMargin = 10;
- m_gemRepoListHeader->resizeSection(0, GemRepoItemDelegate::s_buttonWidth + GemRepoItemDelegate::s_buttonSpacing - 3);
- m_gemRepoListHeader->resizeSection(1, GemRepoItemDelegate::s_nameMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
- m_gemRepoListHeader->resizeSection(2, GemRepoItemDelegate::s_creatorMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
- m_gemRepoListHeader->resizeSection(3, GemRepoItemDelegate::s_updatedMaxWidth + GemRepoItemDelegate::s_contentSpacing - headerExtraMargin);
+ const int headerExtraMargin = 18;
+ m_gemRepoListHeader->resizeSection(0, GemRepoItemDelegate::s_nameMaxWidth + GemRepoItemDelegate::s_contentSpacing + headerExtraMargin);
+ m_gemRepoListHeader->resizeSection(1, GemRepoItemDelegate::s_creatorMaxWidth + GemRepoItemDelegate::s_contentSpacing);
+ m_gemRepoListHeader->resizeSection(2, GemRepoItemDelegate::s_updatedMaxWidth + GemRepoItemDelegate::s_contentSpacing);
// Required to set stylesheet in code as it will not be respected if set in qss
- m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; text-align:left; border-style:none; }");
+ m_gemRepoHeaderTable->horizontalHeader()->setStyleSheet("QHeaderView::section { background-color:transparent; color:white; font-size:12px; border-style:none; }");
middleVLayout->addWidget(m_gemRepoHeaderTable);
m_gemRepoListView = new GemRepoListView(m_gemRepoModel, m_gemRepoModel->GetSelectionModel(), this);
diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp
index 148b8a280c..8a3807c31a 100644
--- a/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp
+++ b/Code/Tools/SceneAPI/SceneData/GraphData/BoneData.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
namespace AZ
@@ -41,6 +42,16 @@ namespace AZ
->DataElement(AZ::Edit::UIHandlers::Default, &BoneData::m_worldTransform, "World", "World transform this bone contributes to the overall skeleton.");
}
}
+
+ BehaviorContext* behaviorContext = azrtti_cast(context);
+ if (behaviorContext)
+ {
+ behaviorContext->Class()
+ ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ ->Attribute(AZ::Script::Attributes::Module, "scene")
+ ->Method("GetWorldTransform", &BoneData::GetWorldTransform);
+ }
}
} // namespace GraphData
} // namespace SceneData
diff --git a/Code/Tools/SceneAPI/SceneData/GraphData/RootBoneData.cpp b/Code/Tools/SceneAPI/SceneData/GraphData/RootBoneData.cpp
index 99cfbf48b9..3d7c8ec376 100644
--- a/Code/Tools/SceneAPI/SceneData/GraphData/RootBoneData.cpp
+++ b/Code/Tools/SceneAPI/SceneData/GraphData/RootBoneData.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
namespace AZ
@@ -30,6 +31,16 @@ namespace AZ
editContext->Class("Root Bone data", "First bone in the skeletal hierarchy.");
}
}
+
+ BehaviorContext* behaviorContext = azrtti_cast(context);
+ if (behaviorContext)
+ {
+ behaviorContext->Class()
+ ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
+ ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
+ ->Attribute(AZ::Script::Attributes::Module, "scene")
+ ->Method("GetWorldTransform", &RootBoneData::GetWorldTransform);
+ }
}
} // namespace GraphData
} // namespace SceneData
diff --git a/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp b/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp
index 4a2d206cc7..59df74a12c 100644
--- a/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp
+++ b/Code/Tools/SceneAPI/SceneData/Tests/GraphData/GraphDataBehaviorTests.cpp
@@ -29,6 +29,8 @@
#include
#include
#include
+#include
+#include
namespace AZ
{
@@ -178,7 +180,18 @@ namespace AZ
materialDataData->SetTexture(AZ::SceneAPI::DataTypes::IMaterialData::TextureMapType::Specular, "specular");
return true;
}
-
+ else if (data.get_type_info().m_id == azrtti_typeid())
+ {
+ auto* boneData = AZStd::any_cast(&data);
+ boneData->SetWorldTransform(SceneAPI::DataTypes::MatrixType::CreateDiagonal({1.0, 2.0, 3.0}));
+ return true;
+ }
+ else if (data.get_type_info().m_id == azrtti_typeid())
+ {
+ auto* boneData = AZStd::any_cast(&data);
+ boneData->SetWorldTransform(SceneAPI::DataTypes::MatrixType::CreateDiagonal({2.0, 3.0, 4.0}));
+ return true;
+ }
return false;
}
@@ -526,6 +539,44 @@ namespace AZ
ExpectExecute("TestExpectTrue(materialData:GetTexture(MaterialData.Roughness) == 'roughness')");
ExpectExecute("TestExpectTrue(materialData:GetTexture(MaterialData.Specular) == 'specular')");
}
+
+ TEST_F(GrapDatahBehaviorScriptTest, SceneGraph_BoneData_AccessWorks)
+ {
+ ExpectExecute("boneData = BoneData()");
+ ExpectExecute("TestExpectTrue(boneData ~= nil)");
+ ExpectExecute("MockGraphData.FillData(boneData)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(0).x, 1.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(0).y, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(0).z, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(0).w, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(1).x, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(1).y, 2.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(1).z, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(1).w, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(2).x, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(2).y, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(2).z, 3.0)");
+ ExpectExecute("TestExpectFloatEquals(boneData:GetWorldTransform():GetRow(2).w, 0.0)");
+ }
+
+ TEST_F(GrapDatahBehaviorScriptTest, SceneGraph_RootBoneData_AccessWorks)
+ {
+ ExpectExecute("rootBoneData = RootBoneData()");
+ ExpectExecute("TestExpectTrue(rootBoneData ~= nil)");
+ ExpectExecute("MockGraphData.FillData(rootBoneData)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(0).x, 2.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(0).y, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(0).z, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(0).w, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(1).x, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(1).y, 3.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(1).z, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(1).w, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(2).x, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(2).y, 0.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(2).z, 4.0)");
+ ExpectExecute("TestExpectFloatEquals(rootBoneData:GetWorldTransform():GetRow(2).w, 0.0)");
+ }
}
}
}
diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h
index a9b06c5bc9..24dfce1dfa 100644
--- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h
+++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionOnQueueRequest.h
@@ -25,11 +25,11 @@ namespace AWSGameLift
AWSGameLiftCreateSessionOnQueueRequest() = default;
virtual ~AWSGameLiftCreateSessionOnQueueRequest() = default;
- // Name of the queue to use to place the new game session. You can use either the queue name or ARN value.
+ //! Name of the queue to use to place the new game session. You can use either the queue name or ARN value.
AZStd::string m_queueName;
- // A unique identifier to assign to the new game session placement. This value is developer-defined.
- // The value must be unique across all Regions and cannot be reused unless you are resubmitting a canceled or timed-out placement request.
+ //! A unique identifier to assign to the new game session placement. This value is developer-defined.
+ //! The value must be unique across all Regions and cannot be reused unless you are resubmitting a canceled or timed-out placement request.
AZStd::string m_placementId;
};
} // namespace AWSGameLift
diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h
index 4fab16ca70..97ffd0b321 100644
--- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h
+++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftCreateSessionRequest.h
@@ -25,14 +25,14 @@ namespace AWSGameLift
AWSGameLiftCreateSessionRequest() = default;
virtual ~AWSGameLiftCreateSessionRequest() = default;
- // A unique identifier for the alias associated with the fleet to create a game session in.
+ //! A unique identifier for the alias associated with the fleet to create a game session in.
AZStd::string m_aliasId;
- // A unique identifier for the fleet to create a game session in.
+ //! A unique identifier for the fleet to create a game session in.
AZStd::string m_fleetId;
- // Custom string that uniquely identifies the new game session request.
- // This is useful for ensuring that game session requests with the same idempotency token are processed only once.
+ //! Custom string that uniquely identifies the new game session request.
+ //! This is useful for ensuring that game session requests with the same idempotency token are processed only once.
AZStd::string m_idempotencyToken;
};
} // namespace AWSGameLift
diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h
index bfc2dc630e..02f3638998 100644
--- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h
+++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftSearchSessionsRequest.h
@@ -25,13 +25,13 @@ namespace AWSGameLift
AWSGameLiftSearchSessionsRequest() = default;
virtual ~AWSGameLiftSearchSessionsRequest() = default;
- // A unique identifier for the alias associated with the fleet to search for active game sessions.
+ //! A unique identifier for the alias associated with the fleet to search for active game sessions.
AZStd::string m_aliasId;
- // A unique identifier for the fleet to search for active game sessions.
+ //! A unique identifier for the fleet to search for active game sessions.
AZStd::string m_fleetId;
- // A fleet location to search for game sessions.
+ //! A fleet location to search for game sessions.
AZStd::string m_location;
};
} // namespace AWSGameLift
diff --git a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h
index ec3719c6d3..b2060032e8 100644
--- a/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h
+++ b/Gems/AWSGameLift/Code/AWSGameLiftClient/Include/Request/AWSGameLiftStartMatchmakingRequest.h
@@ -30,9 +30,10 @@ namespace AWSGameLift
AWSGameLiftStartMatchmakingRequest() = default;
virtual ~AWSGameLiftStartMatchmakingRequest() = default;
- // Name of the matchmaking configuration to use for this request
+ //! Name of the matchmaking configuration to use for this request
AZStd::string m_configurationName;
- // Information on each player to be matched
+
+ //! Information on each player to be matched
AZStd::vector m_players;
};
} // namespace AWSGameLift
diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
index 3f5761270a..84fc58718c 100644
--- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
+++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp
@@ -10,6 +10,7 @@
#include
#include
+#include
#include
#include
#include
@@ -132,7 +133,6 @@ namespace AZ
m_createDefaultScene = false;
}
- AzFramework::AssetCatalogEventBus::Handler::BusConnect();
TickBus::Handler::BusConnect();
// Listen for window system requests (e.g. requests for default window handle)
@@ -143,6 +143,20 @@ namespace AZ
Render::Bootstrap::DefaultWindowBus::Handler::BusConnect();
Render::Bootstrap::RequestBus::Handler::BusConnect();
+
+ // If the settings registry isn't available, something earlier in startup will report that failure.
+ 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*/)
+ {
+ Initialize();
+ },
+ "LegacySystemInterfaceCreated");
+ }
}
void BootstrapSystemComponent::Deactivate()
@@ -153,7 +167,6 @@ namespace AZ
AzFramework::WindowSystemRequestBus::Handler::BusDisconnect();
AzFramework::WindowSystemNotificationBus::Handler::BusDisconnect();
TickBus::Handler::BusDisconnect();
- AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
m_brdfTexture = nullptr;
RemoveRenderPipeline();
@@ -164,14 +177,14 @@ namespace AZ
m_windowHandle = nullptr;
}
- void BootstrapSystemComponent::OnCatalogLoaded(const char* /*catalogFile*/)
+ void BootstrapSystemComponent::Initialize()
{
- if (m_isAssetCatalogLoaded)
+ if (m_isInitialized)
{
return;
}
- m_isAssetCatalogLoaded = true;
+ m_isInitialized = true;
if (!RPI::RPISystemInterface::Get()->IsInitialized())
{
@@ -216,7 +229,7 @@ namespace AZ
{
m_windowHandle = windowHandle;
- if (m_isAssetCatalogLoaded)
+ if (m_isInitialized)
{
CreateWindowContext();
if (m_createDefaultScene)
@@ -259,6 +272,7 @@ namespace AZ
// Create and register a scene with all available feature processors
RPI::SceneDescriptor sceneDesc;
+ sceneDesc.m_nameId = AZ::Name("Main");
AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc);
atomScene->EnableAllFeatureProcessors();
atomScene->Activate();
diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
index 566d19b1a4..74679f5753 100644
--- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
+++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.h
@@ -8,10 +8,10 @@
#pragma once
#include
-#include
#include
+#include
+#include
-#include
#include
#include
#include
@@ -29,7 +29,6 @@
#include
#include
-
namespace AZ
{
namespace Render
@@ -40,7 +39,6 @@ namespace AZ
: public Component
, public TickBus::Handler
, public AzFramework::WindowNotificationBus::Handler
- , public AzFramework::AssetCatalogEventBus::Handler
, public AzFramework::WindowSystemNotificationBus::Handler
, public AzFramework::WindowSystemRequestBus::Handler
, public Render::Bootstrap::DefaultWindowBus::Handler
@@ -82,13 +80,12 @@ namespace AZ
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
int GetTickOrder() override;
- // AzFramework::AssetCatalogEventBus::Handler overrides ...
- void OnCatalogLoaded(const char* catalogFile) override;
-
// AzFramework::WindowSystemNotificationBus::Handler overrides ...
void OnWindowCreated(AzFramework::NativeWindowHandle windowHandle) override;
private:
+ void Initialize();
+
void CreateDefaultRenderPipeline();
void CreateDefaultScene();
void DestroyDefaultScene();
@@ -105,7 +102,7 @@ namespace AZ
RPI::ScenePtr m_defaultScene = nullptr;
AZStd::shared_ptr m_defaultFrameworkScene = nullptr;
- bool m_isAssetCatalogLoaded = false;
+ bool m_isInitialized = false;
// The id of the render pipeline created by this component
RPI::RenderPipelineId m_renderPipelineId;
@@ -119,6 +116,8 @@ namespace AZ
// Maps AZ scenes to RPI scene weak pointers to allow looking up a ScenePtr instead of a raw Scene*
AZStd::unordered_map> m_azSceneToAtomSceneMap;
+
+ AZ::SettingsRegistryInterface::NotifyEventHandler m_componentApplicationLifecycleHandler;
};
} // namespace Bootstrap
} // namespace Render
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
index d36213694b..5de756067a 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype
@@ -1574,15 +1574,6 @@
"shaderOption": "o_baseColor_useTexture"
}
},
- {
- "type": "UseTexture",
- "args": {
- "textureProperty": "metallic.textureMap",
- "useTextureProperty": "metallic.useTexture",
- "dependentProperties": ["metallic.textureMapUv"],
- "shaderOption": "o_metallic_useTexture"
- }
- },
{
"type": "UseTexture",
"args": {
@@ -1649,6 +1640,12 @@
"file": "StandardPBR_Roughness.lua"
}
},
+ {
+ "type": "Lua",
+ "args": {
+ "file": "StandardPBR_Metallic.lua"
+ }
+ },
{
"type": "Lua",
"args": {
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
index 107b525ae4..52befce2b2 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype
@@ -2698,16 +2698,12 @@
}
},
{
- "type": "UseTexture",
+ "type": "Lua",
"args": {
- "textureProperty": "layer1_metallic.textureMap",
- "useTextureProperty": "layer1_metallic.useTexture",
- "dependentProperties": ["layer1_metallic.textureMapUv"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
- "shaderOption": "o_layer1_o_metallic_useTexture"
+ "file": "StandardPBR_Metallic.lua",
+ "propertyNamePrefix": "layer1_",
+ "srgNamePrefix": "m_layer1_",
+ "optionsNamePrefix": "o_layer1_"
}
},
{
@@ -2835,16 +2831,12 @@
}
},
{
- "type": "UseTexture",
+ "type": "Lua",
"args": {
- "textureProperty": "layer2_metallic.textureMap",
- "useTextureProperty": "layer2_metallic.useTexture",
- "dependentProperties": ["layer2_metallic.textureMapUv"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
- "shaderOption": "o_layer2_o_metallic_useTexture"
+ "file": "StandardPBR_Metallic.lua",
+ "propertyNamePrefix": "layer2_",
+ "srgNamePrefix": "m_layer2_",
+ "optionsNamePrefix": "o_layer2_"
}
},
{
@@ -2963,8 +2955,8 @@
"args": {
"textureProperty": "layer3_baseColor.textureMap",
"useTextureProperty": "layer3_baseColor.useTexture",
- "dependentProperties": ["layer3_baseColor.textureMapUv", "layer3_baseColor.textureBlendMode"],
- "shaderTags": [
+ "dependentProperties": [ "layer3_baseColor.textureMapUv", "layer3_baseColor.textureBlendMode" ],
+ "shaderTags": [
"ForwardPass",
"ForwardPass_EDS"
],
@@ -2972,16 +2964,12 @@
}
},
{
- "type": "UseTexture",
+ "type": "Lua",
"args": {
- "textureProperty": "layer3_metallic.textureMap",
- "useTextureProperty": "layer3_metallic.useTexture",
- "dependentProperties": ["layer3_metallic.textureMapUv"],
- "shaderTags": [
- "ForwardPass",
- "ForwardPass_EDS"
- ],
- "shaderOption": "o_layer3_o_metallic_useTexture"
+ "file": "StandardPBR_Metallic.lua",
+ "propertyNamePrefix": "layer3_",
+ "srgNamePrefix": "m_layer3_",
+ "optionsNamePrefix": "o_layer3_"
}
},
{
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
index e0b1949058..f324394309 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype
@@ -1104,15 +1104,6 @@
"shaderOption": "o_baseColor_useTexture"
}
},
- {
- "type": "UseTexture",
- "args": {
- "textureProperty": "metallic.textureMap",
- "useTextureProperty": "metallic.useTexture",
- "dependentProperties": ["metallic.textureMapUv"],
- "shaderOption": "o_metallic_useTexture"
- }
- },
{
"type": "UseTexture",
"args": {
@@ -1179,6 +1170,12 @@
"file": "StandardPBR_Roughness.lua"
}
},
+ {
+ "type": "Lua",
+ "args": {
+ "file": "StandardPBR_Metallic.lua"
+ }
+ },
{
"type": "Lua",
"args": {
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Metallic.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Metallic.lua
new file mode 100644
index 0000000000..69ddbf9c57
--- /dev/null
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Metallic.lua
@@ -0,0 +1,43 @@
+--------------------------------------------------------------------------------------
+--
+-- 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
+--
+--
+--
+----------------------------------------------------------------------------------------------------
+
+function GetMaterialPropertyDependencies()
+ return {"metallic.textureMap", "metallic.useTexture"}
+end
+
+function GetShaderOptionDependencies()
+ return {"o_metallic_useTexture"}
+end
+
+function Process(context)
+ local textureMap = context:GetMaterialPropertyValue_Image("metallic.textureMap")
+ local useTexture = context:GetMaterialPropertyValue_bool("metallic.useTexture")
+ context:SetShaderOptionValue_bool("o_metallic_useTexture", useTexture and textureMap ~= nil)
+end
+
+function ProcessEditor(context)
+ local textureMap = context:GetMaterialPropertyValue_Image("metallic.textureMap")
+ local useTexture = context:GetMaterialPropertyValue_bool("metallic.useTexture")
+
+ if(nil == textureMap) then
+ context:SetMaterialPropertyVisibility("metallic.useTexture", MaterialPropertyVisibility_Hidden)
+ context:SetMaterialPropertyVisibility("metallic.textureMapUv", MaterialPropertyVisibility_Hidden)
+ context:SetMaterialPropertyVisibility("metallic.factor", MaterialPropertyVisibility_Enabled)
+ elseif(not useTexture) then
+ context:SetMaterialPropertyVisibility("metallic.useTexture", MaterialPropertyVisibility_Enabled)
+ context:SetMaterialPropertyVisibility("metallic.textureMapUv", MaterialPropertyVisibility_Disabled)
+ context:SetMaterialPropertyVisibility("metallic.factor", MaterialPropertyVisibility_Enabled)
+ else
+ context:SetMaterialPropertyVisibility("metallic.useTexture", MaterialPropertyVisibility_Enabled)
+ context:SetMaterialPropertyVisibility("metallic.textureMapUv", MaterialPropertyVisibility_Enabled)
+ context:SetMaterialPropertyVisibility("metallic.factor", MaterialPropertyVisibility_Hidden)
+ end
+end
diff --git a/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp
index 2f73269bdf..c9d1e5ae3d 100644
--- a/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp
@@ -19,7 +19,6 @@
#include
#include
#include
-#include
#include
#include