From f22dda1efd46be58b1964fdf71c7e67695009750 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 28 Sep 2021 10:15:54 -0700 Subject: [PATCH 001/200] Enabled Multiplayer gem for AutomatedTesting project. Adding a simple network component and level for testing. (wip) Signed-off-by: Gene Walters --- AutomatedTesting/Gem/Code/CMakeLists.txt | 10 + ...tworkTestPlayerComponent.AutoComponent.xml | 16 + .../Code/Source/AutomatedTestingModule.cpp | 3 + .../AutomatedTestingSystemComponent.cpp | 2 + .../Code/automatedtesting_autogen_files.cmake | 14 + .../Gem/Code/automatedtesting_files.cmake | 1 + AutomatedTesting/Gem/Code/enabled_gems.cmake | 1 + .../Assets/NetworkTestPlayer.scriptcanvas | 2439 +++++++++++++++++ .../MultiplayerTest/Assets/Player.prefab | 236 ++ .../Assets/SimpleScriptPlayer.inputbindings | 45 + .../MultiplayerTest/MultiplayerTest.prefab | 520 ++++ .../Multiplayer/MultiplayerTest/tags.txt | 12 + 12 files changed, 3299 insertions(+) create mode 100644 AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml create mode 100644 AutomatedTesting/Gem/Code/automatedtesting_autogen_files.cmake create mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas create mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings create mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/tags.txt 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 bae8afabb1..112e54d848 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -57,4 +57,5 @@ set(ENABLED_GEMS AudioSystem + Multiplayer ) diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas new file mode 100644 index 0000000000..e97fb53fcb --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas @@ -0,0 +1,2439 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "ScriptCanvasData", + "ClassData": { + "m_scriptCanvas": { + "Id": { + "id": 43360705827261 + }, + "Name": "Untitled-1", + "Components": { + "Component_[12910610729508959793]": { + "$type": "{4D755CA9-AB92-462C-B24F-0B3376F19967} Graph", + "Id": 12910610729508959793, + "m_graphData": { + "m_nodes": [ + { + "Id": { + "id": 43365000794557 + }, + "Name": "SC-Node(InputHandlerNodeableNode)", + "Components": { + "Component_[14357905160005692467]": { + "$type": "InputHandlerNodeableNode", + "Id": 14357905160005692467, + "Slots": [ + { + "id": { + "m_id": "{3D78D840-E4EC-40EE-AEB4-10785F76B433}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Connect Event", + "toolTip": "Connect to input event name as defined in an input binding asset.", + "DisplayGroup": { + "Value": 2173756817 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{135E788B-7835-4EB9-8D25-CB17A7E14D2F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Event Name", + "toolTip": "Event name as defined in an input binding asset. Example 'Fireball'.", + "DisplayGroup": { + "Value": 2173756817 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{A372F63A-E09D-400C-B567-C0BEF6F29068}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "On Connect Event", + "toolTip": "Connect to input event name as defined in an input binding asset.", + "DisplayGroup": { + "Value": 2173756817 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{4AB146FC-E745-43E9-B081-5719E7B4A44A}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Pressed", + "toolTip": "Signaled when the input event begins.", + "DisplayGroup": { + "Value": 458537082 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + }, + { + "id": { + "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "value", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 458537082 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" + } + }, + { + "id": { + "m_id": "{F3531D9F-F690-4A8D-83E2-7C65441D5D0A}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Held", + "toolTip": "Signaled while the input event is active.", + "DisplayGroup": { + "Value": 308119761 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + }, + { + "id": { + "m_id": "{14C7651A-0923-4600-94DE-BC86717F788F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Released", + "toolTip": "Signaled when the input event ends.", + "DisplayGroup": { + "Value": 4215628054 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 5 + }, + "isNullPointer": false, + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "value": "fwdback", + "label": "Event Name" + } + ], + "slotExecutionMap": { + "ins": [ + { + "_slotId": { + "m_id": "{3D78D840-E4EC-40EE-AEB4-10785F76B433}" + }, + "_inputs": [ + { + "_slotId": { + "m_id": "{135E788B-7835-4EB9-8D25-CB17A7E14D2F}" + } + } + ], + "_outs": [ + { + "_slotId": { + "m_id": "{A372F63A-E09D-400C-B567-C0BEF6F29068}" + }, + "_name": "On Connect Event", + "_interfaceSourceId": "{00000000-0000-0000-0000-868924020000}" + } + ], + "_interfaceSourceId": "{80EF7B0D-2502-0000-4062-CF97C8000000}" + } + ], + "latents": [ + { + "_slotId": { + "m_id": "{4AB146FC-E745-43E9-B081-5719E7B4A44A}" + }, + "_name": "Pressed", + "_outputs": [ + { + "_slotId": { + "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" + } + } + ], + "_interfaceSourceId": "{80EF7B0D-2502-0000-4062-CF97C8000000}" + }, + { + "_slotId": { + "m_id": "{F3531D9F-F690-4A8D-83E2-7C65441D5D0A}" + }, + "_name": "Held", + "_outputs": [ + { + "_slotId": { + "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" + } + } + ], + "_interfaceSourceId": "{80EF7B0D-2502-0000-4062-CF97C8000000}" + }, + { + "_slotId": { + "m_id": "{14C7651A-0923-4600-94DE-BC86717F788F}" + }, + "_name": "Released", + "_outputs": [ + { + "_slotId": { + "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" + } + } + ], + "_interfaceSourceId": "{00000000-0000-0000-0000-868924020000}" + } + ] + } + } + } + }, + { + "Id": { + "id": 43382180663741 + }, + "Name": "SC-Node(Print)", + "Components": { + "Component_[14925597173021279]": { + "$type": "Print", + "Id": 14925597173021279, + "Slots": [ + { + "id": { + "m_id": "{EAE9A30D-82B1-4028-B8CA-65982E42A574}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Input signal", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{6F13A374-A4B7-49D4-8B3E-583E5D40AB0B}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "m_format": "NetworkTestPlayer On Graph Start!", + "m_unresolvedString": [ + "NetworkTestPlayer On Graph Start!" + ] + } + } + }, + { + "Id": { + "id": 43377885696445 + }, + "Name": "EBusEventHandler", + "Components": { + "Component_[15351363713064154038]": { + "$type": "EBusEventHandler", + "Id": 15351363713064154038, + "Slots": [ + { + "id": { + "m_id": "{2C35F1BC-5ED7-4D01-84F7-770F0E64C3BD}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Connect", + "toolTip": "Connect this event handler to the specified entity.", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{060E5678-91ED-43F1-85F4-9C67B1F28E8F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Disconnect", + "toolTip": "Disconnect this event handler.", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{9133E024-32E5-46E0-9837-F7D4E56FA748}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "OnConnected", + "toolTip": "Signaled when a connection has taken place.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{DCC59200-087C-4DB8-A6A0-88818969F6A5}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "OnDisconnected", + "toolTip": "Signaled when this event handler is disconnected.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{7EC0BA21-022C-4E7F-9DDA-BF179A6A84AC}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "OnFailure", + "toolTip": "Signaled when it is not possible to connect this handler.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{2FFC9388-51EF-4679-BAC9-DAC2B781965D}" + }, + "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": "{29C797D2-ACBE-4E9D-9BFF-826342AAECB8}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result: NetworkTestPlayerComponentNetworkInput", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{F39360CC-AEE7-435F-8619-AB39C3FFB159}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Number", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{A60446B3-3096-43AC-B563-4F9DE7239E71}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "ExecutionSlot:CreateInput", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + }, + { + "id": { + "m_id": "{F481ABEC-23E7-4E73-A3F8-B9B4ACFD450B}" + }, + "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": "{287AA942-8B38-46B7-AFBC-02772A6A17CE}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Number", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{16E21C35-1FB8-4323-AAFD-2BB6E90DF340}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "ExecutionSlot:ProcessInput", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 1 + }, + "isNullPointer": false, + "$type": "EntityId", + "value": { + "id": 2901262558 + }, + "label": "Source" + }, + { + "isOverloadedStorage": false, + "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": "{A60446B3-3096-43AC-B563-4F9DE7239E71}" + }, + "m_resultSlotId": { + "m_id": "{29C797D2-ACBE-4E9D-9BFF-826342AAECB8}" + }, + "m_parameterSlotIds": [ + { + "m_id": "{F39360CC-AEE7-435F-8619-AB39C3FFB159}" + } + ], + "m_numExpectedArguments": 1 + } + }, + { + "Key": { + "Value": 1793364217 + }, + "Value": { + "m_eventName": "ProcessInput", + "m_eventId": { + "Value": 1793364217 + }, + "m_eventSlotId": { + "m_id": "{16E21C35-1FB8-4323-AAFD-2BB6E90DF340}" + }, + "m_parameterSlotIds": [ + { + "m_id": "{F481ABEC-23E7-4E73-A3F8-B9B4ACFD450B}" + }, + { + "m_id": "{287AA942-8B38-46B7-AFBC-02772A6A17CE}" + } + ], + "m_numExpectedArguments": 2 + } + } + ], + "m_ebusName": "NetworkTestPlayerComponentBusHandler", + "m_busId": { + "Value": 3690077280 + } + } + } + }, + { + "Id": { + "id": 43390770598333 + }, + "Name": "SC-Node(InputHandlerNodeableNode)", + "Components": { + "Component_[2167601062954032864]": { + "$type": "InputHandlerNodeableNode", + "Id": 2167601062954032864, + "Slots": [ + { + "id": { + "m_id": "{2B389100-F09A-4E86-808E-02ABB5B53758}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Connect Event", + "toolTip": "Connect to input event name as defined in an input binding asset.", + "DisplayGroup": { + "Value": 2173756817 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{EA4C841A-0A50-428B-8B18-EEAEDEED9D1B}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Event Name", + "toolTip": "Event name as defined in an input binding asset. Example 'Fireball'.", + "DisplayGroup": { + "Value": 2173756817 + }, + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{58B5F149-BB0A-4451-9E5E-49F1CCC83D04}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "On Connect Event", + "toolTip": "Connect to input event name as defined in an input binding asset.", + "DisplayGroup": { + "Value": 2173756817 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{04E39393-E215-4E13-994D-745373FF287E}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Pressed", + "toolTip": "Signaled when the input event begins.", + "DisplayGroup": { + "Value": 458537082 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + }, + { + "id": { + "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "value", + "DisplayDataType": { + "m_type": 3 + }, + "DisplayGroup": { + "Value": 458537082 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" + } + }, + { + "id": { + "m_id": "{4FB64B09-C0B7-4C75-A88E-768F32971699}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Held", + "toolTip": "Signaled while the input event is active.", + "DisplayGroup": { + "Value": 308119761 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + }, + { + "id": { + "m_id": "{1A1346F5-08E7-4D28-9753-14119B690BE1}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Released", + "toolTip": "Signaled when the input event ends.", + "DisplayGroup": { + "Value": 4215628054 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + }, + "IsLatent": true + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 5 + }, + "isNullPointer": false, + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "value": "leftright", + "label": "Event Name" + } + ], + "slotExecutionMap": { + "ins": [ + { + "_slotId": { + "m_id": "{2B389100-F09A-4E86-808E-02ABB5B53758}" + }, + "_inputs": [ + { + "_slotId": { + "m_id": "{EA4C841A-0A50-428B-8B18-EEAEDEED9D1B}" + } + } + ], + "_outs": [ + { + "_slotId": { + "m_id": "{58B5F149-BB0A-4451-9E5E-49F1CCC83D04}" + }, + "_name": "On Connect Event", + "_interfaceSourceId": "{1863CF97-C800-0000-1863-CF97C8000000}" + } + ], + "_interfaceSourceId": "{E0000080-0000-0000-B930-8377FF7F0000}" + } + ], + "latents": [ + { + "_slotId": { + "m_id": "{04E39393-E215-4E13-994D-745373FF287E}" + }, + "_name": "Pressed", + "_outputs": [ + { + "_slotId": { + "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" + } + } + ], + "_interfaceSourceId": "{E0000080-0000-0000-B930-8377FF7F0000}" + }, + { + "_slotId": { + "m_id": "{4FB64B09-C0B7-4C75-A88E-768F32971699}" + }, + "_name": "Held", + "_outputs": [ + { + "_slotId": { + "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" + } + } + ], + "_interfaceSourceId": "{E0000080-0000-0000-B930-8377FF7F0000}" + }, + { + "_slotId": { + "m_id": "{1A1346F5-08E7-4D28-9753-14119B690BE1}" + }, + "_name": "Released", + "_outputs": [ + { + "_slotId": { + "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" + } + } + ], + "_interfaceSourceId": "{1863CF97-C800-0000-1863-CF97C8000000}" + } + ] + } + } + } + }, + { + "Id": { + "id": 43373590729149 + }, + "Name": "SC-Node(CreateFromValues)", + "Components": { + "Component_[2266778954907791028]": { + "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", + "Id": 2266778954907791028, + "Slots": [ + { + "id": { + "m_id": "{1148FC3F-8CED-46A5-8B63-28A390611175}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "fwdBack", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" + } + }, + { + "id": { + "m_id": "{78FCC8D9-1F62-48F1-B9BB-39D9FFFDAFFD}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "leftRight", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1, + "IsReference": true, + "VariableReference": { + "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" + } + }, + { + "id": { + "m_id": "{65AB115A-40E5-4E50-BDAF-1E3B71948D7D}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{479EDC53-E914-448A-ACDF-60F353DCD1BF}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{90AE3BCB-DC5B-4920-A3FB-315E1848CF5F}" + }, + "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": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "fwdBack" + }, + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "leftRight" + } + ], + "methodType": 2, + "methodName": "CreateFromValues", + "className": "NetworkTestPlayerComponentNetworkInput", + "resultSlotIDs": [ + {} + ], + "inputSlots": [ + { + "m_id": "{1148FC3F-8CED-46A5-8B63-28A390611175}" + }, + { + "m_id": "{78FCC8D9-1F62-48F1-B9BB-39D9FFFDAFFD}" + } + ], + "prettyClassName": "NetworkTestPlayerComponentNetworkInput" + } + } + }, + { + "Id": { + "id": 43369295761853 + }, + "Name": "SC-Node(ExtractProperty)", + "Components": { + "Component_[2721965301691124777]": { + "$type": "ExtractProperty", + "Id": 2721965301691124777, + "Slots": [ + { + "id": { + "m_id": "{BDD084F3-E79A-49E4-B31E-3BDECAE38557}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "When signaled assigns property values using the supplied source input", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{2B9DE6FF-8A3A-460E-8046-6E4C8D597733}" + }, + "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": "{85DDD990-A0FA-4358-8D0C-BD1848865F01}" + }, + "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": "{F393BC87-E1C0-42FB-BFC8-CBAFC133183F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "FwdBack: Number", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{8901EAE6-8571-4D21-B2CD-B72EB9D8B4AC}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "LeftRight: Number", + "DisplayDataType": { + "m_type": 3 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 4, + "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}" + }, + "isNullPointer": true, + "label": "Source" + } + ], + "m_dataType": { + "m_type": 4, + "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}" + }, + "m_propertyAccounts": [ + { + "m_propertySlotId": { + "m_id": "{F393BC87-E1C0-42FB-BFC8-CBAFC133183F}" + }, + "m_propertyType": { + "m_type": 3 + }, + "m_propertyName": "FwdBack" + }, + { + "m_propertySlotId": { + "m_id": "{8901EAE6-8571-4D21-B2CD-B72EB9D8B4AC}" + }, + "m_propertyType": { + "m_type": 3 + }, + "m_propertyName": "LeftRight" + } + ] + } + } + }, + { + "Id": { + "id": 43399360532925 + }, + "Name": "SC-Node((NodeFunctionGenericMultiReturn)<{Vector3(double double double )}* FromValuesTraits >)", + "Components": { + "Component_[3802566169487384355]": { + "$type": "(NodeFunctionGenericMultiReturn)<{Vector3(double double double )}* FromValuesTraits >", + "Id": 3802566169487384355, + "Slots": [ + { + "id": { + "m_id": "{D60FEF03-397A-4C28-9827-D9DF2B8FE175}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{D7E1BDCE-BE8B-4020-8831-9BD49809A289}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{26F42823-8DD1-4024-A0CD-B062A0FA4F11}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Number: X", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{C4F743B5-D2A1-4603-A04B-10CE2C2ACD0E}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Number: Y", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{8AD370E5-72DD-4E4C-A610-6C8AF76CA537}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Number: Z", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{E5BBDE7F-3203-4B3C-B96D-1DE2C7CB3AC2}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result: Vector3", + "DisplayDataType": { + "m_type": 8 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "X" + }, + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Y" + }, + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "Z" + } + ], + "Initialized": true + } + } + }, + { + "Id": { + "id": 43403655500221 + }, + "Name": "SC-Node((NodeFunctionGenericMultiReturn)<{Vector3(Vector3 double )}* MultiplyByNumberTraits >)", + "Components": { + "Component_[4897715661186440639]": { + "$type": "(NodeFunctionGenericMultiReturn)<{Vector3(Vector3 double )}* MultiplyByNumberTraits >", + "Id": 4897715661186440639, + "Slots": [ + { + "id": { + "m_id": "{9BCEF0E6-BB33-424A-8EBE-294936051402}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{4A7A8698-8ADB-4216-A476-481BE2E0A9B3}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{99FFFD91-DA68-473A-8787-C796DF3D5511}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Vector3: Source", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{70DA8430-EBBC-45BC-8C2B-20000EDD9946}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Number: Multiplier", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{A13AC214-5203-4783-ACC9-66A81DDF504F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result: Vector3", + "DisplayDataType": { + "m_type": 8 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 8 + }, + "isNullPointer": false, + "$type": "Vector3", + "value": [ + 0.0, + 0.0, + 0.0 + ], + "label": "Vector3" + }, + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 10.0, + "label": "Number" + } + ], + "Initialized": true + } + } + }, + { + "Id": { + "id": 43395065565629 + }, + "Name": "SC-Node(TryMoveWithVelocity)", + "Components": { + "Component_[5334875941128781927]": { + "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", + "Id": 5334875941128781927, + "Slots": [ + { + "id": { + "m_id": "{2F769976-338F-4BF6-9F4F-0A4B7C6600C5}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "EntityID: 0", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{673A721D-F192-453D-9275-28072095BADC}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Velocity", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{5A7A9B4B-DE5F-417D-9FA6-BCB49356D56F}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "DeltaTime", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 2 + }, + "DataType": 1 + }, + { + "id": { + "m_id": "{86B6BCA1-6ACE-46BF-A0F8-2B1C6956E96A}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{6939D566-D9D7-4AD5-8DD3-A52C60C668EA}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{730D8A55-9723-449F-BB6A-2311CB8F179C}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Result: Vector3", + "DisplayDataType": { + "m_type": 8 + }, + "Descriptor": { + "ConnectionType": 2, + "SlotType": 2 + }, + "DataType": 1 + } + ], + "Datums": [ + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 1 + }, + "isNullPointer": false, + "$type": "EntityId", + "value": { + "id": 2901262558 + }, + "label": "Source" + }, + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 8 + }, + "isNullPointer": false, + "$type": "Vector3", + "value": [ + 0.0, + 0.0, + 0.0 + ], + "label": "Velocity" + }, + { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0, + "label": "DeltaTime" + } + ], + "methodType": 0, + "methodName": "TryMoveWithVelocity", + "className": "NetworkCharacterRequestBus", + "resultSlotIDs": [ + {} + ], + "inputSlots": [ + { + "m_id": "{2F769976-338F-4BF6-9F4F-0A4B7C6600C5}" + }, + { + "m_id": "{673A721D-F192-453D-9275-28072095BADC}" + }, + { + "m_id": "{5A7A9B4B-DE5F-417D-9FA6-BCB49356D56F}" + } + ], + "prettyClassName": "NetworkCharacterRequestBus" + } + } + }, + { + "Id": { + "id": 43386475631037 + }, + "Name": "SC-Node(Start)", + "Components": { + "Component_[9019934049025319126]": { + "$type": "Start", + "Id": 9019934049025319126, + "Slots": [ + { + "id": { + "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "toolTip": "Signaled when the entity that owns this graph is fully activated.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ] + } + } + } + ], + "m_connections": [ + { + "Id": { + "id": 43407950467517 + }, + "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:CreateInput), destEndpoint=(CreateFromValues: In)", + "Components": { + "Component_[18099177567845478364]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 18099177567845478364, + "sourceEndpoint": { + "nodeId": { + "id": 43377885696445 + }, + "slotId": { + "m_id": "{A60446B3-3096-43AC-B563-4F9DE7239E71}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43373590729149 + }, + "slotId": { + "m_id": "{65AB115A-40E5-4E50-BDAF-1E3B71948D7D}" + } + } + } + } + }, + { + "Id": { + "id": 43412245434813 + }, + "Name": "srcEndpoint=(CreateFromValues: Result: NetworkTestPlayerComponentNetworkInput), destEndpoint=(NetworkTestPlayerComponentBusHandler Handler: Result: NetworkTestPlayerComponentNetworkInput)", + "Components": { + "Component_[3440609583154790091]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 3440609583154790091, + "sourceEndpoint": { + "nodeId": { + "id": 43373590729149 + }, + "slotId": { + "m_id": "{90AE3BCB-DC5B-4920-A3FB-315E1848CF5F}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43377885696445 + }, + "slotId": { + "m_id": "{29C797D2-ACBE-4E9D-9BFF-826342AAECB8}" + } + } + } + } + }, + { + "Id": { + "id": 43416540402109 + }, + "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:ProcessInput), destEndpoint=(Extract Properties: In)", + "Components": { + "Component_[14630716581542177252]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 14630716581542177252, + "sourceEndpoint": { + "nodeId": { + "id": 43377885696445 + }, + "slotId": { + "m_id": "{16E21C35-1FB8-4323-AAFD-2BB6E90DF340}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43369295761853 + }, + "slotId": { + "m_id": "{BDD084F3-E79A-49E4-B31E-3BDECAE38557}" + } + } + } + } + }, + { + "Id": { + "id": 43420835369405 + }, + "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: NetworkTestPlayerComponentNetworkInput), destEndpoint=(Extract Properties: Source)", + "Components": { + "Component_[13860510256564725279]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 13860510256564725279, + "sourceEndpoint": { + "nodeId": { + "id": 43377885696445 + }, + "slotId": { + "m_id": "{F481ABEC-23E7-4E73-A3F8-B9B4ACFD450B}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43369295761853 + }, + "slotId": { + "m_id": "{85DDD990-A0FA-4358-8D0C-BD1848865F01}" + } + } + } + } + }, + { + "Id": { + "id": 43425130336701 + }, + "Name": "srcEndpoint=(Extract Properties: Out), destEndpoint=(FromValues: In)", + "Components": { + "Component_[17164744838320571557]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 17164744838320571557, + "sourceEndpoint": { + "nodeId": { + "id": 43369295761853 + }, + "slotId": { + "m_id": "{2B9DE6FF-8A3A-460E-8046-6E4C8D597733}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43399360532925 + }, + "slotId": { + "m_id": "{D60FEF03-397A-4C28-9827-D9DF2B8FE175}" + } + } + } + } + }, + { + "Id": { + "id": 43429425303997 + }, + "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: Number), destEndpoint=(TryMoveWithVelocity: DeltaTime)", + "Components": { + "Component_[23059104859657280]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 23059104859657280, + "sourceEndpoint": { + "nodeId": { + "id": 43377885696445 + }, + "slotId": { + "m_id": "{287AA942-8B38-46B7-AFBC-02772A6A17CE}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43395065565629 + }, + "slotId": { + "m_id": "{5A7A9B4B-DE5F-417D-9FA6-BCB49356D56F}" + } + } + } + } + }, + { + "Id": { + "id": 43433720271293 + }, + "Name": "srcEndpoint=(Extract Properties: FwdBack: Number), destEndpoint=(FromValues: Number: Y)", + "Components": { + "Component_[17404983192645258011]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 17404983192645258011, + "sourceEndpoint": { + "nodeId": { + "id": 43369295761853 + }, + "slotId": { + "m_id": "{F393BC87-E1C0-42FB-BFC8-CBAFC133183F}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43399360532925 + }, + "slotId": { + "m_id": "{C4F743B5-D2A1-4603-A04B-10CE2C2ACD0E}" + } + } + } + } + }, + { + "Id": { + "id": 43438015238589 + }, + "Name": "srcEndpoint=(Extract Properties: LeftRight: Number), destEndpoint=(FromValues: Number: X)", + "Components": { + "Component_[9798097947150010808]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 9798097947150010808, + "sourceEndpoint": { + "nodeId": { + "id": 43369295761853 + }, + "slotId": { + "m_id": "{8901EAE6-8571-4D21-B2CD-B72EB9D8B4AC}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43399360532925 + }, + "slotId": { + "m_id": "{26F42823-8DD1-4024-A0CD-B062A0FA4F11}" + } + } + } + } + }, + { + "Id": { + "id": 43442310205885 + }, + "Name": "srcEndpoint=(FromValues: Out), destEndpoint=(MultiplyByNumber: In)", + "Components": { + "Component_[17451824478145209007]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 17451824478145209007, + "sourceEndpoint": { + "nodeId": { + "id": 43399360532925 + }, + "slotId": { + "m_id": "{D7E1BDCE-BE8B-4020-8831-9BD49809A289}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43403655500221 + }, + "slotId": { + "m_id": "{9BCEF0E6-BB33-424A-8EBE-294936051402}" + } + } + } + } + }, + { + "Id": { + "id": 43446605173181 + }, + "Name": "srcEndpoint=(MultiplyByNumber: Out), destEndpoint=(TryMoveWithVelocity: In)", + "Components": { + "Component_[5558529159234465646]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 5558529159234465646, + "sourceEndpoint": { + "nodeId": { + "id": 43403655500221 + }, + "slotId": { + "m_id": "{4A7A8698-8ADB-4216-A476-481BE2E0A9B3}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43395065565629 + }, + "slotId": { + "m_id": "{86B6BCA1-6ACE-46BF-A0F8-2B1C6956E96A}" + } + } + } + } + }, + { + "Id": { + "id": 43450900140477 + }, + "Name": "srcEndpoint=(FromValues: Result: Vector3), destEndpoint=(MultiplyByNumber: Vector3: Source)", + "Components": { + "Component_[7764617015517277119]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 7764617015517277119, + "sourceEndpoint": { + "nodeId": { + "id": 43399360532925 + }, + "slotId": { + "m_id": "{E5BBDE7F-3203-4B3C-B96D-1DE2C7CB3AC2}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43403655500221 + }, + "slotId": { + "m_id": "{99FFFD91-DA68-473A-8787-C796DF3D5511}" + } + } + } + } + }, + { + "Id": { + "id": 43455195107773 + }, + "Name": "srcEndpoint=(MultiplyByNumber: Result: Vector3), destEndpoint=(TryMoveWithVelocity: Velocity)", + "Components": { + "Component_[2706925113652118995]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 2706925113652118995, + "sourceEndpoint": { + "nodeId": { + "id": 43403655500221 + }, + "slotId": { + "m_id": "{A13AC214-5203-4783-ACC9-66A81DDF504F}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43395065565629 + }, + "slotId": { + "m_id": "{673A721D-F192-453D-9275-28072095BADC}" + } + } + } + } + }, + { + "Id": { + "id": 43459490075069 + }, + "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(InputHandler: Connect Event)", + "Components": { + "Component_[2397369702501938336]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 2397369702501938336, + "sourceEndpoint": { + "nodeId": { + "id": 43386475631037 + }, + "slotId": { + "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43390770598333 + }, + "slotId": { + "m_id": "{2B389100-F09A-4E86-808E-02ABB5B53758}" + } + } + } + } + }, + { + "Id": { + "id": 43463785042365 + }, + "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(InputHandler: Connect Event)", + "Components": { + "Component_[4489728331973570540]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 4489728331973570540, + "sourceEndpoint": { + "nodeId": { + "id": 43386475631037 + }, + "slotId": { + "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43365000794557 + }, + "slotId": { + "m_id": "{3D78D840-E4EC-40EE-AEB4-10785F76B433}" + } + } + } + } + }, + { + "Id": { + "id": 43468080009661 + }, + "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(Print: In)", + "Components": { + "Component_[4010571683585001377]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 4010571683585001377, + "sourceEndpoint": { + "nodeId": { + "id": 43386475631037 + }, + "slotId": { + "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 43382180663741 + }, + "slotId": { + "m_id": "{EAE9A30D-82B1-4028-B8CA-65982E42A574}" + } + } + } + } + } + ] + }, + "m_assetType": "{3E2AC8CD-713F-453E-967F-29517F331784}", + "versionData": { + "_grammarVersion": 1, + "_runtimeVersion": 1, + "_fileVersion": 1 + }, + "m_variableCounter": 3, + "GraphCanvasData": [ + { + "Key": { + "id": 43360705827261 + }, + "Value": { + "ComponentData": { + "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { + "$type": "SceneComponentSaveData", + "ViewParams": { + "Scale": 0.9555062499999998, + "AnchorX": -389.3224182128906, + "AnchorY": 249.08262634277344 + } + } + } + } + }, + { + "Key": { + "id": 43365000794557 + }, + "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": [ + 180.0, + 920.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{33D67E6B-65B7-4A62-A6A0-9625B832C983}" + } + } + } + }, + { + "Key": { + "id": 43369295761853 + }, + "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": [ + 760.0, + 440.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{D2AFA34C-9B74-48D8-86DF-D3BECD3E4142}" + } + } + } + }, + { + "Key": { + "id": 43373590729149 + }, + "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": [ + 760.0, + 240.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".method" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{7450E76B-90F5-4EB2-B250-F8BFCAFFF131}" + } + } + } + }, + { + "Key": { + "id": 43377885696445 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 180.0, + 200.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": "{3B5B4EB1-D272-4F99-BA66-435CE2DF7DC7}" + } + } + } + }, + { + "Key": { + "id": 43382180663741 + }, + "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": [ + 180.0, + 1220.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{09F80A51-F559-4318-8B20-7854E65429E2}" + } + } + } + }, + { + "Key": { + "id": 43386475631037 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "TimeNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + -40.0, + 840.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{B920BAE7-CA6F-47A5-8018-5051C7663AA7}" + } + } + } + }, + { + "Key": { + "id": 43390770598333 + }, + "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": [ + 180.0, + 620.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{A57C469E-705B-4637-A0C1-3D8C1C552133}" + } + } + } + }, + { + "Key": { + "id": 43395065565629 + }, + "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": [ + 1660.0, + 440.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData", + "SubStyle": ".method" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{D5DD4599-509E-46E3-B90A-EB9D4CCAC5BA}" + } + } + } + }, + { + "Key": { + "id": 43399360532925 + }, + "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": [ + 1060.0, + 440.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{0ECE1F31-0C13-4E7B-9793-79645952EE70}" + } + } + } + }, + { + "Key": { + "id": 43403655500221 + }, + "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": [ + 1360.0, + 440.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{1F405B2E-893A-4895-ABD3-F74E86A36786}" + } + } + } + } + ], + "StatisticsHelper": { + "InstanceCounter": [ + { + "Key": 4199610336680704683, + "Value": 1 + }, + { + "Key": 5842116704436214676, + "Value": 1 + }, + { + "Key": 5842116706017748280, + "Value": 1 + }, + { + "Key": 5933558821430063196, + "Value": 1 + }, + { + "Key": 7413323401356093379, + "Value": 2 + }, + { + "Key": 10684225535275896474, + "Value": 1 + }, + { + "Key": 10715014621082578046, + "Value": 1 + }, + { + "Key": 12852262497908180074, + "Value": 1 + }, + { + "Key": 13774516211595206728, + "Value": 1 + }, + { + "Key": 14285852892804039565, + "Value": 1 + } + ] + } + }, + "Component_[314304911617661159]": { + "$type": "EditorGraphVariableManagerComponent", + "Id": 314304911617661159, + "m_variableData": { + "m_nameVariableMap": [ + { + "Key": { + "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" + }, + "Value": { + "Datum": { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0 + }, + "VariableId": { + "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" + }, + "VariableName": "leftright" + } + }, + { + "Key": { + "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" + }, + "Value": { + "Datum": { + "isOverloadedStorage": false, + "scriptCanvasType": { + "m_type": 3 + }, + "isNullPointer": false, + "$type": "double", + "value": 0.0 + }, + "VariableId": { + "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" + }, + "VariableName": "fwdback" + } + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab new file mode 100644 index 0000000000..0505263731 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab @@ -0,0 +1,236 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "Player", + "Components": { + "Component_[10761034584497908401]": { + "$type": "EditorEntitySortComponent", + "Id": 10761034584497908401 + }, + "Component_[11171765958722003650]": { + "$type": "EditorPrefabComponent", + "Id": 11171765958722003650 + }, + "Component_[1122137833969783319]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 1122137833969783319, + "Parent Entity": "" + }, + "Component_[11534770841913162557]": { + "$type": "EditorVisibilityComponent", + "Id": 11534770841913162557 + }, + "Component_[1174143949228204613]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 1174143949228204613 + }, + "Component_[1186621813350148335]": { + "$type": "EditorPendingCompositionComponent", + "Id": 1186621813350148335 + }, + "Component_[13145205368045251727]": { + "$type": "SelectionComponent", + "Id": 13145205368045251727 + }, + "Component_[13555080535184790733]": { + "$type": "EditorOnlyEntityComponent", + "Id": 13555080535184790733 + }, + "Component_[14246542098767318486]": { + "$type": "EditorLockComponent", + "Id": 14246542098767318486 + }, + "Component_[17664598754718527762]": { + "$type": "EditorEntityIconComponent", + "Id": 17664598754718527762 + }, + "Component_[7200122447120227249]": { + "$type": "EditorInspectorComponent", + "Id": 7200122447120227249 + } + } + }, + "Entities": { + "Entity_[45757297578429]": { + "Id": "Entity_[45757297578429]", + "Name": "Player", + "Components": { + "Component_[104121200890756253]": { + "$type": "EditorOnlyEntityComponent", + "Id": 104121200890756253 + }, + "Component_[10427708222806608369]": { + "$type": "SelectionComponent", + "Id": 10427708222806608369 + }, + "Component_[11328301176450343373]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 11328301176450343373 + }, + "Component_[12370308576209604713]": { + "$type": "GenericComponentWrapper", + "Id": 12370308576209604713, + "m_template": { + "$type": "InputConfigurationComponent", + "Input Event Bindings": { + "assetId": { + "guid": "{E24CBF8B-0311-5B09-8B45-174BA05EA21B}" + }, + "assetHint": "levels/multiplayer/multiplayertest/assets/simplescriptplayer.inputbindings" + } + } + }, + "Component_[12445598434074359840]": { + "$type": "GenericComponentWrapper", + "Id": 12445598434074359840, + "m_template": { + "$type": "AutomatedTesting::NetworkTestPlayerComponent" + } + }, + "Component_[1569643966342074001]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 1569643966342074001, + "Parent Entity": "ContainerEntity" + }, + "Component_[1605823397301657756]": { + "$type": "EditorEntityIconComponent", + "Id": 1605823397301657756 + }, + "Component_[16581065267128705530]": { + "$type": "EditorVisibilityComponent", + "Id": 16581065267128705530 + }, + "Component_[17725472297570280383]": { + "$type": "EditorEntitySortComponent", + "Id": 17725472297570280383 + }, + "Component_[18003817796188894025]": { + "$type": "EditorPendingCompositionComponent", + "Id": 18003817796188894025 + }, + "Component_[4561178852583493885]": { + "$type": "GenericComponentWrapper", + "Id": 4561178852583493885, + "m_template": { + "$type": "NetBindComponent" + } + }, + "Component_[6537488149309547572]": { + "$type": "EditorScriptCanvasComponent", + "Id": 6537488149309547572, + "m_name": "NetworkTestPlayer", + "m_assetHolder": { + "m_asset": { + "assetId": { + "guid": "{76BF26E8-1EFF-5823-A7CC-7A53C3E8021C}" + }, + "assetHint": "levels/multiplayer/multiplayertest/assets/networktestplayer.scriptcanvas" + } + }, + "runtimeDataIsValid": true, + "runtimeDataOverrides": { + "source": { + "assetId": { + "guid": "{76BF26E8-1EFF-5823-A7CC-7A53C3E8021C}" + }, + "assetHint": "levels/multiplayer/multiplayertest/assets/networktestplayer.scriptcanvas" + } + } + }, + "Component_[6918074229068073116]": { + "$type": "GenericComponentWrapper", + "Id": 6918074229068073116, + "m_template": { + "$type": "Multiplayer::NetworkTransformComponent" + } + }, + "Component_[7609280163479709008]": { + "$type": "GenericComponentWrapper", + "Id": 7609280163479709008, + "m_template": { + "$type": "Multiplayer::NetworkCharacterComponent" + } + }, + "Component_[7624119531731152716]": { + "$type": "EditorLockComponent", + "Id": 7624119531731152716 + }, + "Component_[7843399643878963565]": { + "$type": "EditorCharacterControllerComponent", + "Id": 7843399643878963565, + "Configuration": { + "entityId": "", + "Material": { + "MaterialIds": [ + {} + ] + } + } + }, + "Component_[869295025943758148]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 869295025943758148, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}", + "subId": 284780167 + }, + "assetHint": "models/sphere.azmodel" + } + } + } + }, + "Component_[8775263112120379398]": { + "$type": "GenericComponentWrapper", + "Id": 8775263112120379398, + "m_template": { + "$type": "Multiplayer::LocalPredictionPlayerInputComponent" + } + }, + "Component_[8829517227774570618]": { + "$type": "EditorInspectorComponent", + "Id": 8829517227774570618, + "ComponentOrderEntryArray": [ + { + "ComponentId": 1569643966342074001 + }, + { + "ComponentId": 12445598434074359840, + "SortIndex": 1 + }, + { + "ComponentId": 8775263112120379398, + "SortIndex": 2 + }, + { + "ComponentId": 6918074229068073116, + "SortIndex": 3 + }, + { + "ComponentId": 4561178852583493885, + "SortIndex": 4 + }, + { + "ComponentId": 6537488149309547572, + "SortIndex": 5 + }, + { + "ComponentId": 7609280163479709008, + "SortIndex": 6 + }, + { + "ComponentId": 7843399643878963565, + "SortIndex": 7 + }, + { + "ComponentId": 12370308576209604713, + "SortIndex": 8 + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings new file mode 100644 index 0000000000..5a95c430c2 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab new file mode 100644 index 0000000000..8c138847ab --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab @@ -0,0 +1,520 @@ +{ + "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 + } + }, + {} + ], + "materialSlotsByLod": [ + [ + { + "id": { + "lodIndex": 0, + "materialSlotStableId": 803645540 + } + } + ], + [ + { + "id": { + "lodIndex": 0 + } + } + ] + ] + }, + "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": 8929576024571800510 + } + } + }, + "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/MultiplayerTest/tags.txt b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/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 From 7eefa90d3659fd45e5b3a190a62229272b2136a1 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 29 Sep 2021 14:08:02 -0700 Subject: [PATCH 002/200] Ensuring AutomatedTest project will include LyShine for server applications. Without LyShine the server app failed to load certain modules which are currently required. Eventually we'll want a way to select render/headless modes per gem Signed-off-by: Gene Walters --- Gems/LyShine/Code/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/LyShine/Code/CMakeLists.txt b/Gems/LyShine/Code/CMakeLists.txt index f8c2ebfd07..77aaa681e0 100644 --- a/Gems/LyShine/Code/CMakeLists.txt +++ b/Gems/LyShine/Code/CMakeLists.txt @@ -52,8 +52,9 @@ ly_add_target( Gem::TextureAtlas ) -# by default, load the above "Gem::LyShine" module in Client applications: +# by default, load the above "Gem::LyShine" module in Client and Server applications: ly_create_alias(NAME LyShine.Clients NAMESPACE Gem TARGETS Gem::LyShine) +ly_create_alias(NAME LyShine.Servers NAMESPACE Gem TARGETS Gem::LyShine) if (PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( From 26079f73509f272923e0984954fc2fe1f663d1ba Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 6 Oct 2021 15:44:43 -0700 Subject: [PATCH 003/200] Update based on feedback. Adding event to MPSystemComponent for receiving a server acceptance packet. The editor system component subscribes to this event and tells the server we're ready for entity updates Signed-off-by: Gene Walters --- .../Code/Include/Multiplayer/IMultiplayer.h | 5 ++++ .../MultiplayerEditorSystemComponent.cpp | 16 ++++++++--- .../Editor/MultiplayerEditorSystemComponent.h | 7 +++++ .../Source/MultiplayerSystemComponent.cpp | 27 ++++++++----------- .../Code/Source/MultiplayerSystemComponent.h | 2 ++ 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h index e32b6188eb..e32a5bd0f3 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/IMultiplayer.h @@ -44,6 +44,7 @@ namespace Multiplayer using ClientDisconnectedEvent = AZ::Event<>; using ConnectionAcquiredEvent = AZ::Event; + using ServerAcceptanceReceivedEvent = AZ::Event<>; using SessionInitEvent = AZ::Event; using SessionShutdownEvent = AZ::Event; @@ -102,6 +103,10 @@ namespace Multiplayer //! @param handler The ConnectionAcquiredEvent Handler to add virtual void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) = 0; + //! Adds a ServerAcceptanceReceived Handler which is invoked when the client receives the accept packet from the server. + //! @param handler The ServerAcceptanceReceived Handler to add + virtual void AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) = 0; + //! Adds a SessionInitEvent Handler which is invoked when a new network session starts. //! @param handler The SessionInitEvent Handler to add virtual void AddSessionInitHandler(SessionInitEvent::Handler& handler) = 0; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index d13c6538db..a08db89f4f 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -62,6 +62,7 @@ namespace Multiplayer } MultiplayerEditorSystemComponent::MultiplayerEditorSystemComponent() + : m_serverAcceptanceReceivedHandler([this](){OnServerAcceptanceReceived();}) { ; } @@ -70,6 +71,7 @@ namespace Multiplayer { AzFramework::GameEntityContextEventBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + AZ::Interface::Get()->AddServerAcceptanceReceivedHandler(m_serverAcceptanceReceivedHandler); } void MultiplayerEditorSystemComponent::Deactivate() @@ -146,10 +148,8 @@ namespace Multiplayer AZStd::replace(projectPath.begin(), projectPath.end(), AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator); AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZStd::string::format( - R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")", - serverPath.c_str(), - projectPath.c_str(), - static_cast(sv_defaultPlayerSpawnAsset).c_str()); + R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")", serverPath.c_str(), + projectPath.c_str(), static_cast(sv_defaultPlayerSpawnAsset).c_str()); processLaunchInfo.m_showWindow = true; processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; @@ -245,4 +245,12 @@ namespace Multiplayer void MultiplayerEditorSystemComponent::OnGameEntitiesReset() { } + + void MultiplayerEditorSystemComponent::OnServerAcceptanceReceived() + { + // We're now accepting the connection to the EditorServer. + // In normal game clients SendReadyForEntityUpdates will be enabled once the appropriate level's root spawnable is loaded, + // but since we're in Editor, we're already in the level. + AZ::Interface::Get()->SendReadyForEntityUpdates(true); + } } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h index 6a9e6a79b6..b1e9335697 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -8,6 +8,8 @@ #pragma once +#include "Multiplayer/IMultiplayer.h" + #include #include @@ -45,6 +47,9 @@ namespace Multiplayer MultiplayerEditorSystemComponent(); ~MultiplayerEditorSystemComponent() override = default; + //! Called once the editor receives the server's accept packet + void OnServerAcceptanceReceived(); + //! AZ::Component overrides. //! @{ void Activate() override; @@ -71,5 +76,7 @@ namespace Multiplayer IEditor* m_editor = nullptr; AzFramework::ProcessWatcher* m_serverProcess = nullptr; AzNetworking::ConnectionId m_editorConnId; + + ServerAcceptanceReceivedEvent::Handler m_serverAcceptanceReceivedHandler; }; } diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 9b04cd98d4..d05139cb41 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -489,23 +489,13 @@ namespace Multiplayer { m_didHandshake = true; - // If this is an Editor then we're now accepting the connection to the EditorServer. - // In normal game clients SendReadyForEntityUpdates will be enabled once the appropriate level's root spawnable is loaded, - // but since we're in Editor, we're already in the level. - AZ::ApplicationTypeQuery applicationType; - AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::QueryApplicationType, applicationType); - if (applicationType.IsEditor()) - { - SendReadyForEntityUpdates(true); - } - else - { - AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); - AZ::Interface::Get()->PerformCommand(commandString.c_str()); + AZ::CVarFixedString commandString = "sv_map " + packet.GetMap(); + AZ::Interface::Get()->PerformCommand(commandString.c_str()); - AZ::CVarFixedString loadLevelString = "LoadLevel " + packet.GetMap(); - AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); - } + AZ::CVarFixedString loadLevelString = "LoadLevel " + packet.GetMap(); + AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); + + m_serverAcceptanceReceivedEvent.Signal(); return true; } @@ -800,6 +790,11 @@ namespace Multiplayer handler.Connect(m_connAcquiredEvent); } + void MultiplayerSystemComponent::AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) + { + handler.Connect(m_serverAcceptanceReceivedEvent); + } + void MultiplayerSystemComponent::AddSessionInitHandler(SessionInitEvent::Handler& handler) { handler.Connect(m_initEvent); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index ba014f814a..4a4cdd4265 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -111,6 +111,7 @@ namespace Multiplayer void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override; void AddSessionInitHandler(SessionInitEvent::Handler& handler) override; void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override; + void AddServerAcceptanceReceivedHandler(ServerAcceptanceReceivedEvent::Handler& handler) override; bool StartHosting(uint16_t port, bool isDedicated = true) override; bool Connect(AZStd::string remoteAddress, uint16_t port) override; void Terminate(AzNetworking::DisconnectReason reason) override; @@ -151,6 +152,7 @@ namespace Multiplayer SessionInitEvent m_initEvent; SessionShutdownEvent m_shutdownEvent; ConnectionAcquiredEvent m_connAcquiredEvent; + ServerAcceptanceReceivedEvent m_serverAcceptanceReceivedEvent; ClientDisconnectedEvent m_clientDisconnectedEvent; AZStd::queue m_pendingConnectionTickets; From f8d1c568fd4e310c26a1a48756d8568dd84903f4 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 6 Oct 2021 16:26:12 -0700 Subject: [PATCH 004/200] can pass in AZ::Utils::GetProjectPath().c_str() directly now that i'm not converting strings Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index a08db89f4f..24c552d9d0 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -144,12 +144,10 @@ namespace Multiplayer } // Start the configured server if it's available - AZStd::string projectPath(AZ::Utils::GetProjectPath().c_str()); - AZStd::replace(projectPath.begin(), projectPath.end(), AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator); AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; processLaunchInfo.m_commandlineParameters = AZStd::string::format( R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")", serverPath.c_str(), - projectPath.c_str(), static_cast(sv_defaultPlayerSpawnAsset).c_str()); + AZ::Utils::GetProjectPath().c_str(), static_cast(sv_defaultPlayerSpawnAsset).c_str()); processLaunchInfo.m_showWindow = true; processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; From 580153b16e68b5825bd9de473e47b0127b631100 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 18 Oct 2021 21:47:40 -0700 Subject: [PATCH 005/200] Adding EditorPython methods to Multiplayer gem for launching the editor gamemode with a server. Adding a test for networkinput with scriptcanvas to ensure the autonomous client can create input and that the server can receive and process the input via script canvas. Signed-off-by: Gene Walters --- .../Gem/PythonTests/CMakeLists.txt | 3 + .../editor_python_test_tools/utils.py | 20 + .../PythonTests/Multiplayer/CMakeLists.txt | 23 + .../PythonTests/Multiplayer/TestSuite_Main.py | 35 + .../Gem/PythonTests/Multiplayer/__init__.py | 6 + .../Multiplayer_AutoComponent_NetworkInput.py | 115 ++ .../AutoComponent_NetworkInput.prefab | 525 +++++ .../AutoComponent_NetworkInput.scriptcanvas | 1827 +++++++++++++++++ .../AutoComponent_NetworkInput/Player.prefab | 196 ++ .../AutoComponent_NetworkInput/tags.txt | 12 + .../Editor/MultiplayerPythonEditorEventsBus.h | 33 + .../Source/Editor/MultiplayerEditorGem.cpp | 1 + .../MultiplayerEditorSystemComponent.cpp | 54 + .../Editor/MultiplayerEditorSystemComponent.h | 23 +- .../Source/MultiplayerSystemComponent.cpp | 25 +- .../multiplayer_editor_shared_files.cmake | 1 + 16 files changed, 2887 insertions(+), 12 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt create mode 100644 AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py create mode 100644 AutomatedTesting/Gem/PythonTests/Multiplayer/__init__.py create mode 100644 AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py create mode 100644 AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/AutoComponent_NetworkInput.scriptcanvas create mode 100644 AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/Player.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/AutoComponent_NetworkInput/tags.txt create mode 100644 Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index 466a4b1679..8bccfb07b6 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -58,3 +58,6 @@ add_subdirectory(smoke) ## AWS ## add_subdirectory(AWS) + +## Multiplayer ## +add_subdirectory(Multiplayer) 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..097b6084a0 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -14,6 +14,7 @@ from typing import Callable, Tuple import azlmbr import azlmbr.legacy.general as general +import azlmbr.multiplayer as multiplayer import azlmbr.debug @@ -66,6 +67,25 @@ 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 + """ + Report.info("Entering game mode") + + if sv_default_player_spawn_asset : + general.set_cvar("sv_defaultPlayerSpawnAsset", sv_default_player_spawn_asset) + + multiplayer.PythonEditorFuncs_enter_game_mode() + + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30.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..950eb861d6 --- /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 + Mutliplayer + ) +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..cf32f76462 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py @@ -0,0 +1,35 @@ +""" +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 + +from .utils.FileManagement import FileManagement as fm + +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..7090b9f2a9 --- /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 saying "AutoComponent_NetworkInput ProcessInput called!" and "AutoComponent_NetworkInput CreateInput called!" + However, if the script receives unexpected values for the Process event we will see "AutoComponent_NetworkInput received bad fwdback" or "AutoComponent_NetworkInput received bad leftright" + + :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) + + # 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/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/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h b/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h new file mode 100644 index 0000000000..39ce4de94a --- /dev/null +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h @@ -0,0 +1,33 @@ +#pragma once +/* + * 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 + +#include + +namespace Multiplayer +{ + /** + * This bus can be used to send commands to the editor. + */ + class MultiplayerEditorLayerPythonRequests + : public AZ::ComponentBus + { + public: + /* + * Enters the editor game mode and launches/connects to the server launcher. + */ + virtual void EnterGameMode() = 0; + + /* + * Queries if it's in the game mode and the server has finished connecting and the default network player has spawned. + */ + virtual bool IsInGameMode() = 0; + }; + using MultiplayerEditorLayerPythonRequestBus = AZ::EBus; +} diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorGem.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorGem.cpp index 65d1f43a64..c922a8683f 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorGem.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorGem.cpp @@ -25,6 +25,7 @@ namespace Multiplayer m_descriptors.end(), { MultiplayerEditorSystemComponent::CreateDescriptor(), + PythonEditorFuncs::CreateDescriptor() }); } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 55a05e33a7..34334996c5 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -37,6 +38,37 @@ namespace Multiplayer AZ_CVAR(AZ::CVarFixedString, editorsv_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the server to connect to"); AZ_CVAR(uint16_t, editorsv_port, DefaultServerEditorPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that the multiplayer editor gem will bind to for traffic"); + ////////////////////////////////////////////////////////////////////////// + void PyEnterGameMode() + { + editorsv_enabled = true; + editorsv_launch = true; + AzToolsFramework::EditorLayerPythonRequestBus::Broadcast(&AzToolsFramework::EditorLayerPythonRequestBus::Events::EnterGameMode); + } + + bool PyIsInGameMode() + { + // If the network entity manager is tracking at least 1 entity then the editor has connected and the autonomous player exists and is being replicated. + return AZ::Interface::Get()->GetEntityCount() > 0; + } + + void PythonEditorFuncs::Reflect(AZ::ReflectContext* context) + { + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + // This will create static python methods in the 'azlmbr.multiplayer' module + // Note: The methods will be prefixed with the class name, PythonEditorFuncs + // Example Hydra Python: azlmbr.multiplayer.PythonEditorFuncs_enter_game_mode() + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "multiplayer") + ->Method("enter_game_mode", PyEnterGameMode, nullptr, "Enters the editor game mode and launches/connects to the server launcher.") + ->Method("is_in_game_mode", PyIsInGameMode, nullptr, "Queries if it's in the game mode and the server has finished connecting and the default network player has spawned.") + ; + + } + } + void MultiplayerEditorSystemComponent::Reflect(AZ::ReflectContext* context) { if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) @@ -44,6 +76,18 @@ namespace Multiplayer serializeContext->Class() ->Version(1); } + + // Reflect Python Editor Functions + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + // This will add the MultiplayerPythonEditorBus into the 'azlmbr.multiplayer' module + behaviorContext->EBus("MultiplayerPythonEditorBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "multiplayer") + ->Event("EnterGameMode", &MultiplayerEditorLayerPythonRequestBus::Events::EnterGameMode) + ->Event("IsInGameMode", &MultiplayerEditorLayerPythonRequestBus::Events::IsInGameMode) + ; + } } void MultiplayerEditorSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) @@ -253,4 +297,14 @@ namespace Multiplayer // but since we're in Editor, we're already in the level. AZ::Interface::Get()->SendReadyForEntityUpdates(true); } + + void MultiplayerEditorSystemComponent::EnterGameMode() + { + PyEnterGameMode(); + } + + bool MultiplayerEditorSystemComponent::IsInGameMode() + { + return PyIsInGameMode(); + } } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h index 4e4c6b677f..de815f3b3c 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -9,7 +9,7 @@ #pragma once #include - +#include #include #include @@ -29,9 +29,24 @@ namespace AzNetworking namespace Multiplayer { + //! A component to reflect scriptable commands for the Editor + class PythonEditorFuncs : public AZ::Component + { + public: + AZ_COMPONENT(PythonEditorFuncs, "{22AEEA59-94E6-4033-B67D-7C8FBB84DF0D}") + + SANDBOX_API static void Reflect(AZ::ReflectContext* context); + + // AZ::Component ... + void Activate() override {} + void Deactivate() override {} + }; + + //! Multiplayer system component wraps the bridging logic between the game and transport layer. class MultiplayerEditorSystemComponent final : public AZ::Component + , public MultiplayerEditorLayerPythonRequestBus::Handler , private AzFramework::GameEntityContextEventBus::Handler , private AzToolsFramework::EditorEvents::Bus::Handler , private IEditorNotifyListener @@ -61,6 +76,12 @@ namespace Multiplayer void NotifyRegisterViews() override; //! @} + //! MultiplayerEditorLayerPythonRequestBus::Handler overrides. + //! @{ + void EnterGameMode() override; + bool IsInGameMode() override; + //! @} + private: //! EditorEvents::Handler overrides //! @{ diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 4fad5697c7..14d6a40887 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -647,11 +647,6 @@ namespace Multiplayer void MultiplayerSystemComponent::OnConnect(AzNetworking::IConnection* connection) { - MultiplayerAgentDatum datum; - datum.m_id = connection->GetConnectionId(); - datum.m_isInvited = false; - datum.m_agentType = MultiplayerAgentType::Client; - AZStd::string providerTicket; if (connection->GetConnectionRole() == ConnectionRole::Connector) { @@ -665,7 +660,12 @@ namespace Multiplayer } else { - AZLOG_INFO("New incoming connection from remote address: %s", connection->GetRemoteAddress().GetString().c_str()); + AZLOG_INFO("New incoming connection from remote address: %s", connection->GetRemoteAddress().GetString().c_str()) + + MultiplayerAgentDatum datum; + datum.m_id = connection->GetConnectionId(); + datum.m_isInvited = false; + datum.m_agentType = MultiplayerAgentType::Client; m_connectionAcquiredEvent.Signal(datum); } @@ -709,15 +709,14 @@ namespace Multiplayer AZLOG_INFO("%s due to %s from remote address: %s", endpointString, reasonString.c_str(), connection->GetRemoteAddress().GetString().c_str()); // The client is disconnecting - if (GetAgentType() == MultiplayerAgentType::Client) + if (m_agentType == MultiplayerAgentType::Client) { AZ_Assert(connection->GetConnectionRole() == ConnectionRole::Connector, "Client connection role should only ever be Connector"); m_clientDisconnectedEvent.Signal(); } - - // Signal to session management that a user has left the server - if (m_agentType == MultiplayerAgentType::DedicatedServer || m_agentType == MultiplayerAgentType::ClientServer) + else if (m_agentType == MultiplayerAgentType::DedicatedServer || m_agentType == MultiplayerAgentType::ClientServer) { + // Signal to session management that a user has left the server if (AZ::Interface::Get() != nullptr && connection->GetConnectionRole() == ConnectionRole::Acceptor) { @@ -1043,7 +1042,11 @@ namespace Multiplayer NetworkEntityHandle MultiplayerSystemComponent::SpawnDefaultPlayerPrefab() { - PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast(sv_defaultPlayerSpawnAsset).c_str())); + // make sure the player prefab path is lowercase (how it's stored in the cache folder) + auto sv_defaultPlayerSpawnAssetLowerCase = static_cast(sv_defaultPlayerSpawnAsset); + AZStd::to_lower(sv_defaultPlayerSpawnAssetLowerCase.begin(), sv_defaultPlayerSpawnAssetLowerCase.end()); + + PrefabEntityId playerPrefabEntityId(AZ::Name(sv_defaultPlayerSpawnAssetLowerCase.c_str())); INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity(), Multiplayer::AutoActivate::DoNotActivate); NetworkEntityHandle controlledEntity; diff --git a/Gems/Multiplayer/Code/multiplayer_editor_shared_files.cmake b/Gems/Multiplayer/Code/multiplayer_editor_shared_files.cmake index 693485143f..cadd908caa 100644 --- a/Gems/Multiplayer/Code/multiplayer_editor_shared_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_editor_shared_files.cmake @@ -13,4 +13,5 @@ set(FILES Source/Editor/MultiplayerEditorGem.h Source/Editor/MultiplayerEditorSystemComponent.cpp Source/Editor/MultiplayerEditorSystemComponent.h + Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h ) From c8237d69c785a369b09365b6e411c774d520c5ed Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 18 Oct 2021 21:57:46 -0700 Subject: [PATCH 006/200] Misc cleanup. Fixing typos and remove unused test level Signed-off-by: Gene Walters --- .../PythonTests/Multiplayer/CMakeLists.txt | 2 +- .../PythonTests/Multiplayer/TestSuite_Main.py | 2 - .../Assets/NetworkTestPlayer.scriptcanvas | 2439 ----------------- .../MultiplayerTest/Assets/Player.prefab | 236 -- .../Assets/SimpleScriptPlayer.inputbindings | 45 - .../MultiplayerTest/MultiplayerTest.prefab | 520 ---- .../Multiplayer/MultiplayerTest/tags.txt | 12 - 7 files changed, 1 insertion(+), 3255 deletions(-) delete mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas delete mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab delete mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings delete mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab delete mode 100644 AutomatedTesting/Levels/Multiplayer/MultiplayerTest/tags.txt diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt index 950eb861d6..5e74d1e93b 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/CMakeLists.txt @@ -18,6 +18,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AutomatedTesting.Assets AutomatedTesting.ServerLauncher COMPONENT - Mutliplayer + Multiplayer ) endif() diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py index cf32f76462..9cecaa7fe8 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Main.py @@ -13,13 +13,11 @@ import pytest import os import sys -from .utils.FileManagement import FileManagement as fm 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): diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas deleted file mode 100644 index e97fb53fcb..0000000000 --- a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/NetworkTestPlayer.scriptcanvas +++ /dev/null @@ -1,2439 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "ScriptCanvasData", - "ClassData": { - "m_scriptCanvas": { - "Id": { - "id": 43360705827261 - }, - "Name": "Untitled-1", - "Components": { - "Component_[12910610729508959793]": { - "$type": "{4D755CA9-AB92-462C-B24F-0B3376F19967} Graph", - "Id": 12910610729508959793, - "m_graphData": { - "m_nodes": [ - { - "Id": { - "id": 43365000794557 - }, - "Name": "SC-Node(InputHandlerNodeableNode)", - "Components": { - "Component_[14357905160005692467]": { - "$type": "InputHandlerNodeableNode", - "Id": 14357905160005692467, - "Slots": [ - { - "id": { - "m_id": "{3D78D840-E4EC-40EE-AEB4-10785F76B433}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Connect Event", - "toolTip": "Connect to input event name as defined in an input binding asset.", - "DisplayGroup": { - "Value": 2173756817 - }, - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{135E788B-7835-4EB9-8D25-CB17A7E14D2F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Event Name", - "toolTip": "Event name as defined in an input binding asset. Example 'Fireball'.", - "DisplayGroup": { - "Value": 2173756817 - }, - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{A372F63A-E09D-400C-B567-C0BEF6F29068}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "On Connect Event", - "toolTip": "Connect to input event name as defined in an input binding asset.", - "DisplayGroup": { - "Value": 2173756817 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{4AB146FC-E745-43E9-B081-5719E7B4A44A}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Pressed", - "toolTip": "Signaled when the input event begins.", - "DisplayGroup": { - "Value": 458537082 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - }, - { - "id": { - "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "value", - "DisplayDataType": { - "m_type": 3 - }, - "DisplayGroup": { - "Value": 458537082 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1, - "IsReference": true, - "VariableReference": { - "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" - } - }, - { - "id": { - "m_id": "{F3531D9F-F690-4A8D-83E2-7C65441D5D0A}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Held", - "toolTip": "Signaled while the input event is active.", - "DisplayGroup": { - "Value": 308119761 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - }, - { - "id": { - "m_id": "{14C7651A-0923-4600-94DE-BC86717F788F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Released", - "toolTip": "Signaled when the input event ends.", - "DisplayGroup": { - "Value": 4215628054 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 5 - }, - "isNullPointer": false, - "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", - "value": "fwdback", - "label": "Event Name" - } - ], - "slotExecutionMap": { - "ins": [ - { - "_slotId": { - "m_id": "{3D78D840-E4EC-40EE-AEB4-10785F76B433}" - }, - "_inputs": [ - { - "_slotId": { - "m_id": "{135E788B-7835-4EB9-8D25-CB17A7E14D2F}" - } - } - ], - "_outs": [ - { - "_slotId": { - "m_id": "{A372F63A-E09D-400C-B567-C0BEF6F29068}" - }, - "_name": "On Connect Event", - "_interfaceSourceId": "{00000000-0000-0000-0000-868924020000}" - } - ], - "_interfaceSourceId": "{80EF7B0D-2502-0000-4062-CF97C8000000}" - } - ], - "latents": [ - { - "_slotId": { - "m_id": "{4AB146FC-E745-43E9-B081-5719E7B4A44A}" - }, - "_name": "Pressed", - "_outputs": [ - { - "_slotId": { - "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" - } - } - ], - "_interfaceSourceId": "{80EF7B0D-2502-0000-4062-CF97C8000000}" - }, - { - "_slotId": { - "m_id": "{F3531D9F-F690-4A8D-83E2-7C65441D5D0A}" - }, - "_name": "Held", - "_outputs": [ - { - "_slotId": { - "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" - } - } - ], - "_interfaceSourceId": "{80EF7B0D-2502-0000-4062-CF97C8000000}" - }, - { - "_slotId": { - "m_id": "{14C7651A-0923-4600-94DE-BC86717F788F}" - }, - "_name": "Released", - "_outputs": [ - { - "_slotId": { - "m_id": "{B04FDDFE-7E31-4FC7-A95E-02E0FC6F2D50}" - } - } - ], - "_interfaceSourceId": "{00000000-0000-0000-0000-868924020000}" - } - ] - } - } - } - }, - { - "Id": { - "id": 43382180663741 - }, - "Name": "SC-Node(Print)", - "Components": { - "Component_[14925597173021279]": { - "$type": "Print", - "Id": 14925597173021279, - "Slots": [ - { - "id": { - "m_id": "{EAE9A30D-82B1-4028-B8CA-65982E42A574}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "In", - "toolTip": "Input signal", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{6F13A374-A4B7-49D4-8B3E-583E5D40AB0B}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Out", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - } - ], - "m_format": "NetworkTestPlayer On Graph Start!", - "m_unresolvedString": [ - "NetworkTestPlayer On Graph Start!" - ] - } - } - }, - { - "Id": { - "id": 43377885696445 - }, - "Name": "EBusEventHandler", - "Components": { - "Component_[15351363713064154038]": { - "$type": "EBusEventHandler", - "Id": 15351363713064154038, - "Slots": [ - { - "id": { - "m_id": "{2C35F1BC-5ED7-4D01-84F7-770F0E64C3BD}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Connect", - "toolTip": "Connect this event handler to the specified entity.", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{060E5678-91ED-43F1-85F4-9C67B1F28E8F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Disconnect", - "toolTip": "Disconnect this event handler.", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{9133E024-32E5-46E0-9837-F7D4E56FA748}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "OnConnected", - "toolTip": "Signaled when a connection has taken place.", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{DCC59200-087C-4DB8-A6A0-88818969F6A5}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "OnDisconnected", - "toolTip": "Signaled when this event handler is disconnected.", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{7EC0BA21-022C-4E7F-9DDA-BF179A6A84AC}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "OnFailure", - "toolTip": "Signaled when it is not possible to connect this handler.", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{2FFC9388-51EF-4679-BAC9-DAC2B781965D}" - }, - "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": "{29C797D2-ACBE-4E9D-9BFF-826342AAECB8}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Result: NetworkTestPlayerComponentNetworkInput", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{F39360CC-AEE7-435F-8619-AB39C3FFB159}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Number", - "DisplayDataType": { - "m_type": 3 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{A60446B3-3096-43AC-B563-4F9DE7239E71}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "ExecutionSlot:CreateInput", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - }, - { - "id": { - "m_id": "{F481ABEC-23E7-4E73-A3F8-B9B4ACFD450B}" - }, - "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": "{287AA942-8B38-46B7-AFBC-02772A6A17CE}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Number", - "DisplayDataType": { - "m_type": 3 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{16E21C35-1FB8-4323-AAFD-2BB6E90DF340}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "ExecutionSlot:ProcessInput", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 1 - }, - "isNullPointer": false, - "$type": "EntityId", - "value": { - "id": 2901262558 - }, - "label": "Source" - }, - { - "isOverloadedStorage": false, - "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": "{A60446B3-3096-43AC-B563-4F9DE7239E71}" - }, - "m_resultSlotId": { - "m_id": "{29C797D2-ACBE-4E9D-9BFF-826342AAECB8}" - }, - "m_parameterSlotIds": [ - { - "m_id": "{F39360CC-AEE7-435F-8619-AB39C3FFB159}" - } - ], - "m_numExpectedArguments": 1 - } - }, - { - "Key": { - "Value": 1793364217 - }, - "Value": { - "m_eventName": "ProcessInput", - "m_eventId": { - "Value": 1793364217 - }, - "m_eventSlotId": { - "m_id": "{16E21C35-1FB8-4323-AAFD-2BB6E90DF340}" - }, - "m_parameterSlotIds": [ - { - "m_id": "{F481ABEC-23E7-4E73-A3F8-B9B4ACFD450B}" - }, - { - "m_id": "{287AA942-8B38-46B7-AFBC-02772A6A17CE}" - } - ], - "m_numExpectedArguments": 2 - } - } - ], - "m_ebusName": "NetworkTestPlayerComponentBusHandler", - "m_busId": { - "Value": 3690077280 - } - } - } - }, - { - "Id": { - "id": 43390770598333 - }, - "Name": "SC-Node(InputHandlerNodeableNode)", - "Components": { - "Component_[2167601062954032864]": { - "$type": "InputHandlerNodeableNode", - "Id": 2167601062954032864, - "Slots": [ - { - "id": { - "m_id": "{2B389100-F09A-4E86-808E-02ABB5B53758}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Connect Event", - "toolTip": "Connect to input event name as defined in an input binding asset.", - "DisplayGroup": { - "Value": 2173756817 - }, - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{EA4C841A-0A50-428B-8B18-EEAEDEED9D1B}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Event Name", - "toolTip": "Event name as defined in an input binding asset. Example 'Fireball'.", - "DisplayGroup": { - "Value": 2173756817 - }, - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{58B5F149-BB0A-4451-9E5E-49F1CCC83D04}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "On Connect Event", - "toolTip": "Connect to input event name as defined in an input binding asset.", - "DisplayGroup": { - "Value": 2173756817 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{04E39393-E215-4E13-994D-745373FF287E}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Pressed", - "toolTip": "Signaled when the input event begins.", - "DisplayGroup": { - "Value": 458537082 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - }, - { - "id": { - "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "value", - "DisplayDataType": { - "m_type": 3 - }, - "DisplayGroup": { - "Value": 458537082 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1, - "IsReference": true, - "VariableReference": { - "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" - } - }, - { - "id": { - "m_id": "{4FB64B09-C0B7-4C75-A88E-768F32971699}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Held", - "toolTip": "Signaled while the input event is active.", - "DisplayGroup": { - "Value": 308119761 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - }, - { - "id": { - "m_id": "{1A1346F5-08E7-4D28-9753-14119B690BE1}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Released", - "toolTip": "Signaled when the input event ends.", - "DisplayGroup": { - "Value": 4215628054 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - }, - "IsLatent": true - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 5 - }, - "isNullPointer": false, - "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", - "value": "leftright", - "label": "Event Name" - } - ], - "slotExecutionMap": { - "ins": [ - { - "_slotId": { - "m_id": "{2B389100-F09A-4E86-808E-02ABB5B53758}" - }, - "_inputs": [ - { - "_slotId": { - "m_id": "{EA4C841A-0A50-428B-8B18-EEAEDEED9D1B}" - } - } - ], - "_outs": [ - { - "_slotId": { - "m_id": "{58B5F149-BB0A-4451-9E5E-49F1CCC83D04}" - }, - "_name": "On Connect Event", - "_interfaceSourceId": "{1863CF97-C800-0000-1863-CF97C8000000}" - } - ], - "_interfaceSourceId": "{E0000080-0000-0000-B930-8377FF7F0000}" - } - ], - "latents": [ - { - "_slotId": { - "m_id": "{04E39393-E215-4E13-994D-745373FF287E}" - }, - "_name": "Pressed", - "_outputs": [ - { - "_slotId": { - "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" - } - } - ], - "_interfaceSourceId": "{E0000080-0000-0000-B930-8377FF7F0000}" - }, - { - "_slotId": { - "m_id": "{4FB64B09-C0B7-4C75-A88E-768F32971699}" - }, - "_name": "Held", - "_outputs": [ - { - "_slotId": { - "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" - } - } - ], - "_interfaceSourceId": "{E0000080-0000-0000-B930-8377FF7F0000}" - }, - { - "_slotId": { - "m_id": "{1A1346F5-08E7-4D28-9753-14119B690BE1}" - }, - "_name": "Released", - "_outputs": [ - { - "_slotId": { - "m_id": "{89E5C5FE-4AF8-49D6-AE4F-E7C0E793439F}" - } - } - ], - "_interfaceSourceId": "{1863CF97-C800-0000-1863-CF97C8000000}" - } - ] - } - } - } - }, - { - "Id": { - "id": 43373590729149 - }, - "Name": "SC-Node(CreateFromValues)", - "Components": { - "Component_[2266778954907791028]": { - "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", - "Id": 2266778954907791028, - "Slots": [ - { - "id": { - "m_id": "{1148FC3F-8CED-46A5-8B63-28A390611175}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "fwdBack", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1, - "IsReference": true, - "VariableReference": { - "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" - } - }, - { - "id": { - "m_id": "{78FCC8D9-1F62-48F1-B9BB-39D9FFFDAFFD}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "leftRight", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1, - "IsReference": true, - "VariableReference": { - "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" - } - }, - { - "id": { - "m_id": "{65AB115A-40E5-4E50-BDAF-1E3B71948D7D}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "In", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{479EDC53-E914-448A-ACDF-60F353DCD1BF}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Out", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{90AE3BCB-DC5B-4920-A3FB-315E1848CF5F}" - }, - "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": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0, - "label": "fwdBack" - }, - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0, - "label": "leftRight" - } - ], - "methodType": 2, - "methodName": "CreateFromValues", - "className": "NetworkTestPlayerComponentNetworkInput", - "resultSlotIDs": [ - {} - ], - "inputSlots": [ - { - "m_id": "{1148FC3F-8CED-46A5-8B63-28A390611175}" - }, - { - "m_id": "{78FCC8D9-1F62-48F1-B9BB-39D9FFFDAFFD}" - } - ], - "prettyClassName": "NetworkTestPlayerComponentNetworkInput" - } - } - }, - { - "Id": { - "id": 43369295761853 - }, - "Name": "SC-Node(ExtractProperty)", - "Components": { - "Component_[2721965301691124777]": { - "$type": "ExtractProperty", - "Id": 2721965301691124777, - "Slots": [ - { - "id": { - "m_id": "{BDD084F3-E79A-49E4-B31E-3BDECAE38557}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "In", - "toolTip": "When signaled assigns property values using the supplied source input", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{2B9DE6FF-8A3A-460E-8046-6E4C8D597733}" - }, - "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": "{85DDD990-A0FA-4358-8D0C-BD1848865F01}" - }, - "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": "{F393BC87-E1C0-42FB-BFC8-CBAFC133183F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "FwdBack: Number", - "DisplayDataType": { - "m_type": 3 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{8901EAE6-8571-4D21-B2CD-B72EB9D8B4AC}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "LeftRight: Number", - "DisplayDataType": { - "m_type": 3 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 4, - "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}" - }, - "isNullPointer": true, - "label": "Source" - } - ], - "m_dataType": { - "m_type": 4, - "m_azType": "{12A1776B-61F6-4E5F-356A-AD718A62051F}" - }, - "m_propertyAccounts": [ - { - "m_propertySlotId": { - "m_id": "{F393BC87-E1C0-42FB-BFC8-CBAFC133183F}" - }, - "m_propertyType": { - "m_type": 3 - }, - "m_propertyName": "FwdBack" - }, - { - "m_propertySlotId": { - "m_id": "{8901EAE6-8571-4D21-B2CD-B72EB9D8B4AC}" - }, - "m_propertyType": { - "m_type": 3 - }, - "m_propertyName": "LeftRight" - } - ] - } - } - }, - { - "Id": { - "id": 43399360532925 - }, - "Name": "SC-Node((NodeFunctionGenericMultiReturn)<{Vector3(double double double )}* FromValuesTraits >)", - "Components": { - "Component_[3802566169487384355]": { - "$type": "(NodeFunctionGenericMultiReturn)<{Vector3(double double double )}* FromValuesTraits >", - "Id": 3802566169487384355, - "Slots": [ - { - "id": { - "m_id": "{D60FEF03-397A-4C28-9827-D9DF2B8FE175}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "In", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{D7E1BDCE-BE8B-4020-8831-9BD49809A289}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Out", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{26F42823-8DD1-4024-A0CD-B062A0FA4F11}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Number: X", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{C4F743B5-D2A1-4603-A04B-10CE2C2ACD0E}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Number: Y", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{8AD370E5-72DD-4E4C-A610-6C8AF76CA537}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Number: Z", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{E5BBDE7F-3203-4B3C-B96D-1DE2C7CB3AC2}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Result: Vector3", - "DisplayDataType": { - "m_type": 8 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0, - "label": "X" - }, - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0, - "label": "Y" - }, - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0, - "label": "Z" - } - ], - "Initialized": true - } - } - }, - { - "Id": { - "id": 43403655500221 - }, - "Name": "SC-Node((NodeFunctionGenericMultiReturn)<{Vector3(Vector3 double )}* MultiplyByNumberTraits >)", - "Components": { - "Component_[4897715661186440639]": { - "$type": "(NodeFunctionGenericMultiReturn)<{Vector3(Vector3 double )}* MultiplyByNumberTraits >", - "Id": 4897715661186440639, - "Slots": [ - { - "id": { - "m_id": "{9BCEF0E6-BB33-424A-8EBE-294936051402}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "In", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{4A7A8698-8ADB-4216-A476-481BE2E0A9B3}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Out", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{99FFFD91-DA68-473A-8787-C796DF3D5511}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Vector3: Source", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{70DA8430-EBBC-45BC-8C2B-20000EDD9946}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Number: Multiplier", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{A13AC214-5203-4783-ACC9-66A81DDF504F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Result: Vector3", - "DisplayDataType": { - "m_type": 8 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 8 - }, - "isNullPointer": false, - "$type": "Vector3", - "value": [ - 0.0, - 0.0, - 0.0 - ], - "label": "Vector3" - }, - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 10.0, - "label": "Number" - } - ], - "Initialized": true - } - } - }, - { - "Id": { - "id": 43395065565629 - }, - "Name": "SC-Node(TryMoveWithVelocity)", - "Components": { - "Component_[5334875941128781927]": { - "$type": "{E42861BD-1956-45AE-8DD7-CCFC1E3E5ACF} Method", - "Id": 5334875941128781927, - "Slots": [ - { - "id": { - "m_id": "{2F769976-338F-4BF6-9F4F-0A4B7C6600C5}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "EntityID: 0", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{673A721D-F192-453D-9275-28072095BADC}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Velocity", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{5A7A9B4B-DE5F-417D-9FA6-BCB49356D56F}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "DeltaTime", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 2 - }, - "DataType": 1 - }, - { - "id": { - "m_id": "{86B6BCA1-6ACE-46BF-A0F8-2B1C6956E96A}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "In", - "Descriptor": { - "ConnectionType": 1, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{6939D566-D9D7-4AD5-8DD3-A52C60C668EA}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Out", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - }, - { - "id": { - "m_id": "{730D8A55-9723-449F-BB6A-2311CB8F179C}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Result: Vector3", - "DisplayDataType": { - "m_type": 8 - }, - "Descriptor": { - "ConnectionType": 2, - "SlotType": 2 - }, - "DataType": 1 - } - ], - "Datums": [ - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 1 - }, - "isNullPointer": false, - "$type": "EntityId", - "value": { - "id": 2901262558 - }, - "label": "Source" - }, - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 8 - }, - "isNullPointer": false, - "$type": "Vector3", - "value": [ - 0.0, - 0.0, - 0.0 - ], - "label": "Velocity" - }, - { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0, - "label": "DeltaTime" - } - ], - "methodType": 0, - "methodName": "TryMoveWithVelocity", - "className": "NetworkCharacterRequestBus", - "resultSlotIDs": [ - {} - ], - "inputSlots": [ - { - "m_id": "{2F769976-338F-4BF6-9F4F-0A4B7C6600C5}" - }, - { - "m_id": "{673A721D-F192-453D-9275-28072095BADC}" - }, - { - "m_id": "{5A7A9B4B-DE5F-417D-9FA6-BCB49356D56F}" - } - ], - "prettyClassName": "NetworkCharacterRequestBus" - } - } - }, - { - "Id": { - "id": 43386475631037 - }, - "Name": "SC-Node(Start)", - "Components": { - "Component_[9019934049025319126]": { - "$type": "Start", - "Id": 9019934049025319126, - "Slots": [ - { - "id": { - "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" - }, - "contracts": [ - { - "$type": "SlotTypeContract" - } - ], - "slotName": "Out", - "toolTip": "Signaled when the entity that owns this graph is fully activated.", - "Descriptor": { - "ConnectionType": 2, - "SlotType": 1 - } - } - ] - } - } - } - ], - "m_connections": [ - { - "Id": { - "id": 43407950467517 - }, - "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:CreateInput), destEndpoint=(CreateFromValues: In)", - "Components": { - "Component_[18099177567845478364]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 18099177567845478364, - "sourceEndpoint": { - "nodeId": { - "id": 43377885696445 - }, - "slotId": { - "m_id": "{A60446B3-3096-43AC-B563-4F9DE7239E71}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43373590729149 - }, - "slotId": { - "m_id": "{65AB115A-40E5-4E50-BDAF-1E3B71948D7D}" - } - } - } - } - }, - { - "Id": { - "id": 43412245434813 - }, - "Name": "srcEndpoint=(CreateFromValues: Result: NetworkTestPlayerComponentNetworkInput), destEndpoint=(NetworkTestPlayerComponentBusHandler Handler: Result: NetworkTestPlayerComponentNetworkInput)", - "Components": { - "Component_[3440609583154790091]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 3440609583154790091, - "sourceEndpoint": { - "nodeId": { - "id": 43373590729149 - }, - "slotId": { - "m_id": "{90AE3BCB-DC5B-4920-A3FB-315E1848CF5F}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43377885696445 - }, - "slotId": { - "m_id": "{29C797D2-ACBE-4E9D-9BFF-826342AAECB8}" - } - } - } - } - }, - { - "Id": { - "id": 43416540402109 - }, - "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: ExecutionSlot:ProcessInput), destEndpoint=(Extract Properties: In)", - "Components": { - "Component_[14630716581542177252]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 14630716581542177252, - "sourceEndpoint": { - "nodeId": { - "id": 43377885696445 - }, - "slotId": { - "m_id": "{16E21C35-1FB8-4323-AAFD-2BB6E90DF340}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43369295761853 - }, - "slotId": { - "m_id": "{BDD084F3-E79A-49E4-B31E-3BDECAE38557}" - } - } - } - } - }, - { - "Id": { - "id": 43420835369405 - }, - "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: NetworkTestPlayerComponentNetworkInput), destEndpoint=(Extract Properties: Source)", - "Components": { - "Component_[13860510256564725279]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 13860510256564725279, - "sourceEndpoint": { - "nodeId": { - "id": 43377885696445 - }, - "slotId": { - "m_id": "{F481ABEC-23E7-4E73-A3F8-B9B4ACFD450B}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43369295761853 - }, - "slotId": { - "m_id": "{85DDD990-A0FA-4358-8D0C-BD1848865F01}" - } - } - } - } - }, - { - "Id": { - "id": 43425130336701 - }, - "Name": "srcEndpoint=(Extract Properties: Out), destEndpoint=(FromValues: In)", - "Components": { - "Component_[17164744838320571557]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 17164744838320571557, - "sourceEndpoint": { - "nodeId": { - "id": 43369295761853 - }, - "slotId": { - "m_id": "{2B9DE6FF-8A3A-460E-8046-6E4C8D597733}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43399360532925 - }, - "slotId": { - "m_id": "{D60FEF03-397A-4C28-9827-D9DF2B8FE175}" - } - } - } - } - }, - { - "Id": { - "id": 43429425303997 - }, - "Name": "srcEndpoint=(NetworkTestPlayerComponentBusHandler Handler: Number), destEndpoint=(TryMoveWithVelocity: DeltaTime)", - "Components": { - "Component_[23059104859657280]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 23059104859657280, - "sourceEndpoint": { - "nodeId": { - "id": 43377885696445 - }, - "slotId": { - "m_id": "{287AA942-8B38-46B7-AFBC-02772A6A17CE}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43395065565629 - }, - "slotId": { - "m_id": "{5A7A9B4B-DE5F-417D-9FA6-BCB49356D56F}" - } - } - } - } - }, - { - "Id": { - "id": 43433720271293 - }, - "Name": "srcEndpoint=(Extract Properties: FwdBack: Number), destEndpoint=(FromValues: Number: Y)", - "Components": { - "Component_[17404983192645258011]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 17404983192645258011, - "sourceEndpoint": { - "nodeId": { - "id": 43369295761853 - }, - "slotId": { - "m_id": "{F393BC87-E1C0-42FB-BFC8-CBAFC133183F}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43399360532925 - }, - "slotId": { - "m_id": "{C4F743B5-D2A1-4603-A04B-10CE2C2ACD0E}" - } - } - } - } - }, - { - "Id": { - "id": 43438015238589 - }, - "Name": "srcEndpoint=(Extract Properties: LeftRight: Number), destEndpoint=(FromValues: Number: X)", - "Components": { - "Component_[9798097947150010808]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 9798097947150010808, - "sourceEndpoint": { - "nodeId": { - "id": 43369295761853 - }, - "slotId": { - "m_id": "{8901EAE6-8571-4D21-B2CD-B72EB9D8B4AC}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43399360532925 - }, - "slotId": { - "m_id": "{26F42823-8DD1-4024-A0CD-B062A0FA4F11}" - } - } - } - } - }, - { - "Id": { - "id": 43442310205885 - }, - "Name": "srcEndpoint=(FromValues: Out), destEndpoint=(MultiplyByNumber: In)", - "Components": { - "Component_[17451824478145209007]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 17451824478145209007, - "sourceEndpoint": { - "nodeId": { - "id": 43399360532925 - }, - "slotId": { - "m_id": "{D7E1BDCE-BE8B-4020-8831-9BD49809A289}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43403655500221 - }, - "slotId": { - "m_id": "{9BCEF0E6-BB33-424A-8EBE-294936051402}" - } - } - } - } - }, - { - "Id": { - "id": 43446605173181 - }, - "Name": "srcEndpoint=(MultiplyByNumber: Out), destEndpoint=(TryMoveWithVelocity: In)", - "Components": { - "Component_[5558529159234465646]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 5558529159234465646, - "sourceEndpoint": { - "nodeId": { - "id": 43403655500221 - }, - "slotId": { - "m_id": "{4A7A8698-8ADB-4216-A476-481BE2E0A9B3}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43395065565629 - }, - "slotId": { - "m_id": "{86B6BCA1-6ACE-46BF-A0F8-2B1C6956E96A}" - } - } - } - } - }, - { - "Id": { - "id": 43450900140477 - }, - "Name": "srcEndpoint=(FromValues: Result: Vector3), destEndpoint=(MultiplyByNumber: Vector3: Source)", - "Components": { - "Component_[7764617015517277119]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 7764617015517277119, - "sourceEndpoint": { - "nodeId": { - "id": 43399360532925 - }, - "slotId": { - "m_id": "{E5BBDE7F-3203-4B3C-B96D-1DE2C7CB3AC2}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43403655500221 - }, - "slotId": { - "m_id": "{99FFFD91-DA68-473A-8787-C796DF3D5511}" - } - } - } - } - }, - { - "Id": { - "id": 43455195107773 - }, - "Name": "srcEndpoint=(MultiplyByNumber: Result: Vector3), destEndpoint=(TryMoveWithVelocity: Velocity)", - "Components": { - "Component_[2706925113652118995]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 2706925113652118995, - "sourceEndpoint": { - "nodeId": { - "id": 43403655500221 - }, - "slotId": { - "m_id": "{A13AC214-5203-4783-ACC9-66A81DDF504F}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43395065565629 - }, - "slotId": { - "m_id": "{673A721D-F192-453D-9275-28072095BADC}" - } - } - } - } - }, - { - "Id": { - "id": 43459490075069 - }, - "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(InputHandler: Connect Event)", - "Components": { - "Component_[2397369702501938336]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 2397369702501938336, - "sourceEndpoint": { - "nodeId": { - "id": 43386475631037 - }, - "slotId": { - "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43390770598333 - }, - "slotId": { - "m_id": "{2B389100-F09A-4E86-808E-02ABB5B53758}" - } - } - } - } - }, - { - "Id": { - "id": 43463785042365 - }, - "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(InputHandler: Connect Event)", - "Components": { - "Component_[4489728331973570540]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 4489728331973570540, - "sourceEndpoint": { - "nodeId": { - "id": 43386475631037 - }, - "slotId": { - "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43365000794557 - }, - "slotId": { - "m_id": "{3D78D840-E4EC-40EE-AEB4-10785F76B433}" - } - } - } - } - }, - { - "Id": { - "id": 43468080009661 - }, - "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(Print: In)", - "Components": { - "Component_[4010571683585001377]": { - "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", - "Id": 4010571683585001377, - "sourceEndpoint": { - "nodeId": { - "id": 43386475631037 - }, - "slotId": { - "m_id": "{E0763D25-A7BF-4129-97E0-505CB19577FD}" - } - }, - "targetEndpoint": { - "nodeId": { - "id": 43382180663741 - }, - "slotId": { - "m_id": "{EAE9A30D-82B1-4028-B8CA-65982E42A574}" - } - } - } - } - } - ] - }, - "m_assetType": "{3E2AC8CD-713F-453E-967F-29517F331784}", - "versionData": { - "_grammarVersion": 1, - "_runtimeVersion": 1, - "_fileVersion": 1 - }, - "m_variableCounter": 3, - "GraphCanvasData": [ - { - "Key": { - "id": 43360705827261 - }, - "Value": { - "ComponentData": { - "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { - "$type": "SceneComponentSaveData", - "ViewParams": { - "Scale": 0.9555062499999998, - "AnchorX": -389.3224182128906, - "AnchorY": 249.08262634277344 - } - } - } - } - }, - { - "Key": { - "id": 43365000794557 - }, - "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": [ - 180.0, - 920.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{33D67E6B-65B7-4A62-A6A0-9625B832C983}" - } - } - } - }, - { - "Key": { - "id": 43369295761853 - }, - "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": [ - 760.0, - 440.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{D2AFA34C-9B74-48D8-86DF-D3BECD3E4142}" - } - } - } - }, - { - "Key": { - "id": 43373590729149 - }, - "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": [ - 760.0, - 240.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData", - "SubStyle": ".method" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{7450E76B-90F5-4EB2-B250-F8BFCAFFF131}" - } - } - } - }, - { - "Key": { - "id": 43377885696445 - }, - "Value": { - "ComponentData": { - "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { - "$type": "NodeSaveData" - }, - "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { - "$type": "GeometrySaveData", - "Position": [ - 180.0, - 200.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": "{3B5B4EB1-D272-4F99-BA66-435CE2DF7DC7}" - } - } - } - }, - { - "Key": { - "id": 43382180663741 - }, - "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": [ - 180.0, - 1220.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{09F80A51-F559-4318-8B20-7854E65429E2}" - } - } - } - }, - { - "Key": { - "id": 43386475631037 - }, - "Value": { - "ComponentData": { - "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { - "$type": "NodeSaveData" - }, - "{328FF15C-C302-458F-A43D-E1794DE0904E}": { - "$type": "GeneralNodeTitleComponentSaveData", - "PaletteOverride": "TimeNodeTitlePalette" - }, - "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { - "$type": "GeometrySaveData", - "Position": [ - -40.0, - 840.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{B920BAE7-CA6F-47A5-8018-5051C7663AA7}" - } - } - } - }, - { - "Key": { - "id": 43390770598333 - }, - "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": [ - 180.0, - 620.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{A57C469E-705B-4637-A0C1-3D8C1C552133}" - } - } - } - }, - { - "Key": { - "id": 43395065565629 - }, - "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": [ - 1660.0, - 440.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData", - "SubStyle": ".method" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{D5DD4599-509E-46E3-B90A-EB9D4CCAC5BA}" - } - } - } - }, - { - "Key": { - "id": 43399360532925 - }, - "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": [ - 1060.0, - 440.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{0ECE1F31-0C13-4E7B-9793-79645952EE70}" - } - } - } - }, - { - "Key": { - "id": 43403655500221 - }, - "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": [ - 1360.0, - 440.0 - ] - }, - "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { - "$type": "StylingComponentSaveData" - }, - "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { - "$type": "PersistentIdComponentSaveData", - "PersistentId": "{1F405B2E-893A-4895-ABD3-F74E86A36786}" - } - } - } - } - ], - "StatisticsHelper": { - "InstanceCounter": [ - { - "Key": 4199610336680704683, - "Value": 1 - }, - { - "Key": 5842116704436214676, - "Value": 1 - }, - { - "Key": 5842116706017748280, - "Value": 1 - }, - { - "Key": 5933558821430063196, - "Value": 1 - }, - { - "Key": 7413323401356093379, - "Value": 2 - }, - { - "Key": 10684225535275896474, - "Value": 1 - }, - { - "Key": 10715014621082578046, - "Value": 1 - }, - { - "Key": 12852262497908180074, - "Value": 1 - }, - { - "Key": 13774516211595206728, - "Value": 1 - }, - { - "Key": 14285852892804039565, - "Value": 1 - } - ] - } - }, - "Component_[314304911617661159]": { - "$type": "EditorGraphVariableManagerComponent", - "Id": 314304911617661159, - "m_variableData": { - "m_nameVariableMap": [ - { - "Key": { - "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" - }, - "Value": { - "Datum": { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0 - }, - "VariableId": { - "m_id": "{663251D4-450B-4A61-AECA-7AB29B229107}" - }, - "VariableName": "leftright" - } - }, - { - "Key": { - "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" - }, - "Value": { - "Datum": { - "isOverloadedStorage": false, - "scriptCanvasType": { - "m_type": 3 - }, - "isNullPointer": false, - "$type": "double", - "value": 0.0 - }, - "VariableId": { - "m_id": "{6704B457-6C06-4D1F-976B-4314CB7BAE4A}" - }, - "VariableName": "fwdback" - } - } - ] - } - } - } - } - } -} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab deleted file mode 100644 index 0505263731..0000000000 --- a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/Player.prefab +++ /dev/null @@ -1,236 +0,0 @@ -{ - "ContainerEntity": { - "Id": "ContainerEntity", - "Name": "Player", - "Components": { - "Component_[10761034584497908401]": { - "$type": "EditorEntitySortComponent", - "Id": 10761034584497908401 - }, - "Component_[11171765958722003650]": { - "$type": "EditorPrefabComponent", - "Id": 11171765958722003650 - }, - "Component_[1122137833969783319]": { - "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", - "Id": 1122137833969783319, - "Parent Entity": "" - }, - "Component_[11534770841913162557]": { - "$type": "EditorVisibilityComponent", - "Id": 11534770841913162557 - }, - "Component_[1174143949228204613]": { - "$type": "EditorDisabledCompositionComponent", - "Id": 1174143949228204613 - }, - "Component_[1186621813350148335]": { - "$type": "EditorPendingCompositionComponent", - "Id": 1186621813350148335 - }, - "Component_[13145205368045251727]": { - "$type": "SelectionComponent", - "Id": 13145205368045251727 - }, - "Component_[13555080535184790733]": { - "$type": "EditorOnlyEntityComponent", - "Id": 13555080535184790733 - }, - "Component_[14246542098767318486]": { - "$type": "EditorLockComponent", - "Id": 14246542098767318486 - }, - "Component_[17664598754718527762]": { - "$type": "EditorEntityIconComponent", - "Id": 17664598754718527762 - }, - "Component_[7200122447120227249]": { - "$type": "EditorInspectorComponent", - "Id": 7200122447120227249 - } - } - }, - "Entities": { - "Entity_[45757297578429]": { - "Id": "Entity_[45757297578429]", - "Name": "Player", - "Components": { - "Component_[104121200890756253]": { - "$type": "EditorOnlyEntityComponent", - "Id": 104121200890756253 - }, - "Component_[10427708222806608369]": { - "$type": "SelectionComponent", - "Id": 10427708222806608369 - }, - "Component_[11328301176450343373]": { - "$type": "EditorDisabledCompositionComponent", - "Id": 11328301176450343373 - }, - "Component_[12370308576209604713]": { - "$type": "GenericComponentWrapper", - "Id": 12370308576209604713, - "m_template": { - "$type": "InputConfigurationComponent", - "Input Event Bindings": { - "assetId": { - "guid": "{E24CBF8B-0311-5B09-8B45-174BA05EA21B}" - }, - "assetHint": "levels/multiplayer/multiplayertest/assets/simplescriptplayer.inputbindings" - } - } - }, - "Component_[12445598434074359840]": { - "$type": "GenericComponentWrapper", - "Id": 12445598434074359840, - "m_template": { - "$type": "AutomatedTesting::NetworkTestPlayerComponent" - } - }, - "Component_[1569643966342074001]": { - "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", - "Id": 1569643966342074001, - "Parent Entity": "ContainerEntity" - }, - "Component_[1605823397301657756]": { - "$type": "EditorEntityIconComponent", - "Id": 1605823397301657756 - }, - "Component_[16581065267128705530]": { - "$type": "EditorVisibilityComponent", - "Id": 16581065267128705530 - }, - "Component_[17725472297570280383]": { - "$type": "EditorEntitySortComponent", - "Id": 17725472297570280383 - }, - "Component_[18003817796188894025]": { - "$type": "EditorPendingCompositionComponent", - "Id": 18003817796188894025 - }, - "Component_[4561178852583493885]": { - "$type": "GenericComponentWrapper", - "Id": 4561178852583493885, - "m_template": { - "$type": "NetBindComponent" - } - }, - "Component_[6537488149309547572]": { - "$type": "EditorScriptCanvasComponent", - "Id": 6537488149309547572, - "m_name": "NetworkTestPlayer", - "m_assetHolder": { - "m_asset": { - "assetId": { - "guid": "{76BF26E8-1EFF-5823-A7CC-7A53C3E8021C}" - }, - "assetHint": "levels/multiplayer/multiplayertest/assets/networktestplayer.scriptcanvas" - } - }, - "runtimeDataIsValid": true, - "runtimeDataOverrides": { - "source": { - "assetId": { - "guid": "{76BF26E8-1EFF-5823-A7CC-7A53C3E8021C}" - }, - "assetHint": "levels/multiplayer/multiplayertest/assets/networktestplayer.scriptcanvas" - } - } - }, - "Component_[6918074229068073116]": { - "$type": "GenericComponentWrapper", - "Id": 6918074229068073116, - "m_template": { - "$type": "Multiplayer::NetworkTransformComponent" - } - }, - "Component_[7609280163479709008]": { - "$type": "GenericComponentWrapper", - "Id": 7609280163479709008, - "m_template": { - "$type": "Multiplayer::NetworkCharacterComponent" - } - }, - "Component_[7624119531731152716]": { - "$type": "EditorLockComponent", - "Id": 7624119531731152716 - }, - "Component_[7843399643878963565]": { - "$type": "EditorCharacterControllerComponent", - "Id": 7843399643878963565, - "Configuration": { - "entityId": "", - "Material": { - "MaterialIds": [ - {} - ] - } - } - }, - "Component_[869295025943758148]": { - "$type": "AZ::Render::EditorMeshComponent", - "Id": 869295025943758148, - "Controller": { - "Configuration": { - "ModelAsset": { - "assetId": { - "guid": "{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}", - "subId": 284780167 - }, - "assetHint": "models/sphere.azmodel" - } - } - } - }, - "Component_[8775263112120379398]": { - "$type": "GenericComponentWrapper", - "Id": 8775263112120379398, - "m_template": { - "$type": "Multiplayer::LocalPredictionPlayerInputComponent" - } - }, - "Component_[8829517227774570618]": { - "$type": "EditorInspectorComponent", - "Id": 8829517227774570618, - "ComponentOrderEntryArray": [ - { - "ComponentId": 1569643966342074001 - }, - { - "ComponentId": 12445598434074359840, - "SortIndex": 1 - }, - { - "ComponentId": 8775263112120379398, - "SortIndex": 2 - }, - { - "ComponentId": 6918074229068073116, - "SortIndex": 3 - }, - { - "ComponentId": 4561178852583493885, - "SortIndex": 4 - }, - { - "ComponentId": 6537488149309547572, - "SortIndex": 5 - }, - { - "ComponentId": 7609280163479709008, - "SortIndex": 6 - }, - { - "ComponentId": 7843399643878963565, - "SortIndex": 7 - }, - { - "ComponentId": 12370308576209604713, - "SortIndex": 8 - } - ] - } - } - } - } -} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings deleted file mode 100644 index 5a95c430c2..0000000000 --- a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/Assets/SimpleScriptPlayer.inputbindings +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab deleted file mode 100644 index 8c138847ab..0000000000 --- a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/MultiplayerTest.prefab +++ /dev/null @@ -1,520 +0,0 @@ -{ - "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 - } - }, - {} - ], - "materialSlotsByLod": [ - [ - { - "id": { - "lodIndex": 0, - "materialSlotStableId": 803645540 - } - } - ], - [ - { - "id": { - "lodIndex": 0 - } - } - ] - ] - }, - "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": 8929576024571800510 - } - } - }, - "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/MultiplayerTest/tags.txt b/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/tags.txt deleted file mode 100644 index 0d6c1880e7..0000000000 --- a/AutomatedTesting/Levels/Multiplayer/MultiplayerTest/tags.txt +++ /dev/null @@ -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,0,0 From 928cfcf1e53dd44b642878fad4c0a31e336c8115 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 19 Oct 2021 09:49:56 -0700 Subject: [PATCH 007/200] Removing an accidental pragma once Signed-off-by: Gene Walters --- .../Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h b/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h index 39ce4de94a..90f968f591 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h @@ -1,4 +1,3 @@ -#pragma once /* * 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. From 5e8b6da8b24594d2f221774816f441ba5b435a36 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 19 Oct 2021 15:04:46 -0700 Subject: [PATCH 008/200] Ensure editor server launches with the same render hardware interface as the editor. This way when Automated Review runs the Multiplayer tests with the headless editor, by default the server launcher will also be headless (rhi=null). Also added a cvar to override the default rhi (editorsv_rhi_override); this way if you're in the normal editor with a gui, you can launch a headless server Signed-off-by: Gene Walters --- Gems/Multiplayer/Code/CMakeLists.txt | 2 ++ .../Editor/MultiplayerEditorSystemComponent.cpp | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/CMakeLists.txt b/Gems/Multiplayer/Code/CMakeLists.txt index 909590a25d..b0dcb971b0 100644 --- a/Gems/Multiplayer/Code/CMakeLists.txt +++ b/Gems/Multiplayer/Code/CMakeLists.txt @@ -149,6 +149,8 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS) AZ::AzFramework AZ::AzNetworking AZ::AzToolsFramework + Gem::Atom_RPI.Public + Gem::Atom_RHI.Reflect Gem::Multiplayer.Static Gem::Multiplayer.Builders ) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 34334996c5..4dcbea6cea 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace Multiplayer { @@ -37,6 +38,8 @@ namespace Multiplayer "The server executable that should be run. Empty to use the current project's ServerLauncher"); AZ_CVAR(AZ::CVarFixedString, editorsv_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the server to connect to"); AZ_CVAR(uint16_t, editorsv_port, DefaultServerEditorPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that the multiplayer editor gem will bind to for traffic"); + AZ_CVAR(AZ::CVarFixedString, editorsv_rhi_override, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, + "Override the default rendering hardware interface (rhi) when launching the Editor server. For example, you may be running an Editor using 'dx12', but want to launch a headless server using 'null'. If empty the server will launch using the same rhi as the Editor."); ////////////////////////////////////////////////////////////////////////// void PyEnterGameMode() @@ -189,11 +192,21 @@ namespace Multiplayer // Start the configured server if it's available AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + + // Open the server launcher using the same rhi as the editor (or launch with the override rhi) + AZ::Name server_rhi = AZ::RPI::RPISystemInterface::Get()->GetRenderApiName(); + if (!static_cast(editorsv_rhi_override).empty()) + { + server_rhi = static_cast(editorsv_rhi_override); + } + processLaunchInfo.m_commandlineParameters = AZStd::string::format( - R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s")", + R"("%s" --project-path "%s" --editorsv_isDedicated true --sv_defaultPlayerSpawnAsset "%s" --rhi "%s")", serverPath.c_str(), AZ::Utils::GetProjectPath().c_str(), - static_cast(sv_defaultPlayerSpawnAsset).c_str()); + static_cast(sv_defaultPlayerSpawnAsset).c_str(), + server_rhi.GetCStr() + ); processLaunchInfo.m_showWindow = true; processLaunchInfo.m_processPriority = AzFramework::ProcessPriority::PROCESSPRIORITY_NORMAL; From dd6c9b940352b88a625fd506997a8930534dda9f Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 19 Oct 2021 16:10:11 -0700 Subject: [PATCH 009/200] Misc code comment changes based on PR feedback Signed-off-by: Gene Walters --- .../tests/Multiplayer_AutoComponent_NetworkInput.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py index 7090b9f2a9..fe727b2506 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py @@ -34,8 +34,8 @@ def Multiplayer_AutoComponent_NetworkInput(): Expected Outcome: - We should see editor logs saying "AutoComponent_NetworkInput ProcessInput called!" and "AutoComponent_NetworkInput CreateInput called!" - However, if the script receives unexpected values for the Process event we will see "AutoComponent_NetworkInput received bad fwdback" or "AutoComponent_NetworkInput received bad leftright" + 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: """ From 322e3395436eeb6c94597d52edd7bfd4a6dc008e Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 20 Oct 2021 11:45:42 -0700 Subject: [PATCH 010/200] Printing error if the editor server launcher has not been built. Updating pytest to fail if the serverlauncher does not exist. Signed-off-by: Gene Walters --- .../editor_python_test_tools/utils.py | 15 +++++++++++---- .../Editor/MultiplayerEditorSystemComponent.cpp | 4 ++++ 2 files changed, 15 insertions(+), 4 deletions(-) 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 097b6084a0..d6f33a1726 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -77,12 +77,19 @@ class TestHelper: :return: None """ Report.info("Entering game mode") - if sv_default_player_spawn_asset : general.set_cvar("sv_defaultPlayerSpawnAsset", sv_default_player_spawn_asset) - - multiplayer.PythonEditorFuncs_enter_game_mode() - + + with Tracer() as section_tracer: + multiplayer.PythonEditorFuncs_enter_game_mode() + general.idle_wait_frames(1) + + # Make sure the server launcher binary exists + unexpected_line = "LaunchEditorServer failed! The ServerLauncher binary is missing!" + found_lines = [printInfo.message.strip() for printInfo in section_tracer.errors] + found_unexpected_lines = [x for x in found_lines if unexpected_line in x] + Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30.0) Report.critical_result(msgtuple_success_fail, multiplayer.PythonEditorFuncs_is_in_game_mode()) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 4dcbea6cea..17095778fe 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -214,6 +214,10 @@ namespace Multiplayer AzFramework::ProcessWatcher* outProcess = AzFramework::ProcessWatcher::LaunchProcess( processLaunchInfo, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE); + AZ_Error( + "MultiplayerEditor", processLaunchInfo.m_launchResult != AzFramework::ProcessLauncher::ProcessLaunchResult::PLR_MissingFile, + "LaunchEditorServer failed! The ServerLauncher binary is missing! (%s) Please build server launcher.", serverPath.c_str()) + return outProcess; } From 9ef70d2ae7b6a5da5619b9f23f1fb99c5162e079 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 20 Oct 2021 16:38:39 -0700 Subject: [PATCH 011/200] Debugging why Jenkins is failing. Changing a harmless assert to a warning to check if this allows server launcher to run on Jenkins machine. Not sure why this would work, just grabbing at straws Signed-off-by: Gene Walters --- Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp | 2 +- .../ly_remote_console/remote_console_commands.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index b2b67c3b75..ad15abd2b7 100644 --- a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -152,7 +152,7 @@ namespace LegacyLevelSystem // [LYN-2376] Remove once legacy slice support is removed int SpawnableLevelSystem::GetLevelCount() { - AZ_Assert(false, "GetLevelCount - No longer supported."); + AZ_Warning("SpawnableLevelSystem", false, "GetLevelCount - No longer supported."); return 0; } diff --git a/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py b/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py index 559823c820..31ec6663fb 100755 --- a/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py +++ b/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py @@ -228,7 +228,7 @@ class RemoteConsole: def expect_log_line(self, match_string, timeout=30): # type: (str, int) -> bool """ - Looks for a log line event to expect within a time frame. Returns False is timeout is reached. + Looks for a log line event to expect within a time frame. Returns False if timeout is reached. :param match_string: The string to match that acts as a key :param timeout: The timeout to wait for the log line in seconds :return: boolean True if match_string found, False otherwise. From 55c96e9eb1333f0b63aa25a6f2fbf4e0058008d5 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 20 Oct 2021 17:22:33 -0700 Subject: [PATCH 012/200] Revert after testing! Printing the entire server log in order to see gather information on Jenkins machine Signed-off-by: Gene Walters --- .../editor_python_test_tools/utils.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) 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 d6f33a1726..1928f2342b 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -83,7 +83,7 @@ class TestHelper: with Tracer() as section_tracer: multiplayer.PythonEditorFuncs_enter_game_mode() general.idle_wait_frames(1) - + # Make sure the server launcher binary exists unexpected_line = "LaunchEditorServer failed! The ServerLauncher binary is missing!" found_lines = [printInfo.message.strip() for printInfo in section_tracer.errors] @@ -91,6 +91,23 @@ class TestHelper: Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30.0) + + # @todo delete! debugging Jenkins + Report.info("PRINTING THE ENTIRE SERVER LOG!") + + serverlog_filename = os.path.join(os.getcwd(), 'AutomatedTesting/user/log/Server.log') + + with open(serverlog_filename) as server_log_file: + Report.info( server_log_file.read() ) + Report.info("END: PRINTING THE ENTIRE SERVER LOG") + + #if not multiplayer.PythonEditorFuncs_is_in_game_mode(): + # 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 + # for line in expected_lines_server: + # assert server_console.expect_log_line(line, EXPECTEDLINE_WAIT_TIME_SECONDS), f"Expected line not found: {line}" + + Report.critical_result(msgtuple_success_fail, multiplayer.PythonEditorFuncs_is_in_game_mode()) @staticmethod From b81bf1064ffbdec3d435e52dcc9a85e034ce5b40 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 20 Oct 2021 23:33:22 -0700 Subject: [PATCH 013/200] Noticing the Jenkins machine fails to connect to server before the server logs even begin. Giving the server some time (5 seconds) to boot up before trying to connect to see if that helps Signed-off-by: Gene Walters --- .../Source/Editor/MultiplayerEditorSystemComponent.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 17095778fe..89783699b0 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -255,6 +255,15 @@ namespace Multiplayer if (editorsv_launch && LocalHost == remoteAddress) { m_serverProcess = LaunchEditorServer(); + + AZ_Warning( + "MultiplayerEditor", false, + "Just launched LaunchEditorServer. About to sleep!"); + + AZStd::this_thread::sleep_for(AZStd::chrono::seconds(5.0)); + + AZ_Warning("MultiplayerEditor", false, "Just launched LaunchEditorServer. Done sleeping!"); + } // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets From 3a1c377c031ed756e20cda2259fdcc630f8b450f Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 21 Oct 2021 06:23:51 -0700 Subject: [PATCH 014/200] Fix compiler warning Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 89783699b0..d84603feaa 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -260,7 +260,7 @@ namespace Multiplayer "MultiplayerEditor", false, "Just launched LaunchEditorServer. About to sleep!"); - AZStd::this_thread::sleep_for(AZStd::chrono::seconds(5.0)); + AZStd::this_thread::sleep_for(AZStd::chrono::seconds(10)); AZ_Warning("MultiplayerEditor", false, "Just launched LaunchEditorServer. Done sleeping!"); From 43d1fbeedd2bf7c506990f75092cf6a544476f70 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 21 Oct 2021 06:39:17 -0700 Subject: [PATCH 015/200] Adding more logging to debug TcpNetworkInterface Signed-off-by: Gene Walters --- .../AzNetworking/TcpTransport/TcpNetworkInterface.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp index 1ccff7be50..c2d9f5f1d2 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp @@ -79,6 +79,8 @@ namespace AzNetworking ConnectionId TcpNetworkInterface::Connect(const IpAddress& remoteAddress) { + AZLOG_INFO("Attemping TcpNetworkInterface::Connect") + const ConnectionId connectionId = m_connectionSet.GetNextConnectionId(); AZStd::unique_ptr connection = AZStd::make_unique(connectionId, remoteAddress, *this, m_trustZone, net_TcpUseEncryption); AZ_Assert(connection->GetConnectionRole() == ConnectionRole::Connector, "Invalid role for connection"); @@ -87,6 +89,9 @@ namespace AzNetworking TcpSocket* tcpSocket = connection->GetTcpSocket(); if (tcpSocket == nullptr) { + AZLOG_ERROR( + "TcpNetworkInterface::Connect tcpSocket is null! How can this be? Returning InvalidConnectionId") + return InvalidConnectionId; } From f7af0b8d5256c68c5914510e0f0f02dc2b56da5a Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 21 Oct 2021 06:51:49 -0700 Subject: [PATCH 016/200] Adding more logging to debug TcpSocket on Jenkins machine Signed-off-by: Gene Walters --- .../AzNetworking/TcpTransport/TcpSocket.cpp | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp index e469b70640..f3b62e1913 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp @@ -68,13 +68,30 @@ namespace AzNetworking { Close(); - if (!SocketCreateInternal() - || !BindSocketForConnectInternal(address) - || !(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd))) + if (!SocketCreateInternal()) + { + AZ_Warning("TcpSocket", false, "Tcp::Connect failed. SocketCreateInternal is false"); + + Close(); + return false; + } + + if (!BindSocketForConnectInternal(address)) { + AZ_Warning("TcpSocket", false, "Tcp::Connect failed. BindSocketForConnectInternal is false"); + + Close(); + return false; + } + + if (!(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd))) + { + AZ_Warning("TcpSocket", false, "Tcp::Connect failed. SetSocketNonBlocking and SetSocketNoDelay is false"); + Close(); return false; } + return true; } From 6b102cadacb0f3d387a642399653cbcbf8d8a1db Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 21 Oct 2021 09:56:03 -0700 Subject: [PATCH 017/200] Removing hacked Jenkins fix in order to rerun with more logging and get a better idea of why its failing in the first place Signed-off-by: Gene Walters --- .../Source/Editor/MultiplayerEditorSystemComponent.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index d84603feaa..4e1b13f152 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -256,13 +256,13 @@ namespace Multiplayer { m_serverProcess = LaunchEditorServer(); - AZ_Warning( - "MultiplayerEditor", false, - "Just launched LaunchEditorServer. About to sleep!"); + //AZ_Warning( + // "MultiplayerEditor", false, + // "Just launched LaunchEditorServer. About to sleep!") - AZStd::this_thread::sleep_for(AZStd::chrono::seconds(10)); + //AZStd::this_thread::sleep_for(AZStd::chrono::seconds(10)); - AZ_Warning("MultiplayerEditor", false, "Just launched LaunchEditorServer. Done sleeping!"); + //AZ_Warning("MultiplayerEditor", false, "Just launched LaunchEditorServer. Done sleeping!") } From 0c5110b1ed618e0e51246139eba58743a5563cd2 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 22 Oct 2021 16:34:42 -0700 Subject: [PATCH 018/200] Fix a race condition where the editor tries to connect to the editor-server before the editor-server is ready (originally discovered on lower-spec Jenkin machines). Change editor-server so that editor waits to receive a EditorServerReadyForInit before trying to send all the level data. Signed-off-by: Gene Walters --- .../Multiplayer/MultiplayerEditorServerBus.h | 24 +++ .../AutoGen/MultiplayerEditor.AutoPackets.xml | 4 +- .../Editor/MultiplayerEditorConnection.cpp | 32 +++- .../Editor/MultiplayerEditorConnection.h | 1 + .../MultiplayerEditorSystemComponent.cpp | 141 ++++++++++++------ .../Editor/MultiplayerEditorSystemComponent.h | 8 +- Gems/Multiplayer/Code/multiplayer_files.cmake | 1 + 7 files changed, 162 insertions(+), 49 deletions(-) create mode 100644 Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerEditorServerBus.h diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerEditorServerBus.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerEditorServerBus.h new file mode 100644 index 0000000000..570aa500ef --- /dev/null +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerEditorServerBus.h @@ -0,0 +1,24 @@ +/* + * 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 + +#include + +namespace Multiplayer +{ + class MultiplayerEditorServerRequests : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + + virtual void SendEditorServerInitPacket(AzNetworking::IConnection* connection) = 0; + }; + using MultiplayerEditorServerRequestBus = AZ::EBus; +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml index dd553a2413..2ee5c76172 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/MultiplayerEditor.AutoPackets.xml @@ -4,7 +4,9 @@ - + + + diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index a30ab207b4..fb0b86af6a 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -35,13 +36,25 @@ namespace Multiplayer m_networkEditorInterface->SetTimeoutMs(AZ::TimeMs{ 0 }); // Disable timeouts on this network interface if (editorsv_isDedicated) { - uint16_t editorServerPort = DefaultServerEditorPort; - if (auto console = AZ::Interface::Get(); console) + uint16_t editorsv_port = DefaultServerEditorPort; + if (const auto console = AZ::Interface::Get()) + { + console->GetCvarValue("editorsv_port", editorsv_port); + } + AZ_Assert(m_networkEditorInterface, "MP Editor Network Interface was unregistered before Editor Server could start listening.") + + // Check if there's already an Editor out there waiting to connect + ConnectionId editorServerToEditorConnectionId = m_networkEditorInterface->Connect(IpAddress(LocalHost.data(), editorsv_port, ProtocolType::Tcp)); + + // If there wasn't an Editor waiting for this server to start, then assume this is an editor-server launched by hand... listen and wait for the editor to request a connection + if (editorServerToEditorConnectionId == AzNetworking::InvalidConnectionId) + { + m_networkEditorInterface->Listen(editorsv_port); + } + else { - console->GetCvarValue("editorsv_port", editorServerPort); + m_networkEditorInterface->SendReliablePacket(editorServerToEditorConnectionId, MultiplayerEditorPackets::EditorServerReadyForInit()); } - AZ_Assert(m_networkEditorInterface, "MP Editor Network Interface was unregistered before Editor Server could start listening."); - m_networkEditorInterface->Listen(editorServerPort); } } @@ -125,6 +138,15 @@ namespace Multiplayer return true; } + bool MultiplayerEditorConnection::HandleRequest( + [[maybe_unused]] AzNetworking::IConnection* connection, + [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader, + [[maybe_unused]] MultiplayerEditorPackets::EditorServerReadyForInit& packet) + { + MultiplayerEditorServerRequestBus::Broadcast(&MultiplayerEditorServerRequestBus::Events::SendEditorServerInitPacket, connection); + return true; + } + bool MultiplayerEditorConnection::HandleRequest ( [[maybe_unused]] AzNetworking::IConnection* connection, diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h index b93c830cd0..392f573729 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h @@ -33,6 +33,7 @@ namespace Multiplayer MultiplayerEditorConnection(); ~MultiplayerEditorConnection() = default; + bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReadyForInit& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerInit& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerEditorPackets::EditorServerReady& packet); diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 55a05e33a7..0878dbd8cb 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -71,6 +71,7 @@ namespace Multiplayer { AzFramework::GameEntityContextEventBus::Handler::BusConnect(); AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + MultiplayerEditorServerRequestBus::Handler::BusConnect(); AZ::Interface::Get()->AddServerAcceptanceReceivedHandler(m_serverAcceptanceReceivedHandler); } @@ -78,6 +79,7 @@ namespace Multiplayer { AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); AzFramework::GameEntityContextEventBus::Handler::BusDisconnect(); + MultiplayerEditorServerRequestBus::Handler::BusDisconnect(); } void MultiplayerEditorSystemComponent::NotifyRegisterViews() @@ -107,8 +109,8 @@ namespace Multiplayer m_serverProcess->TerminateProcess(0); m_serverProcess = nullptr; } - INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpEditorInterfaceName)); - if (editorNetworkInterface) + + if (INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpEditorInterfaceName))) { editorNetworkInterface->Disconnect(m_editorConnId, AzNetworking::DisconnectReason::TerminatedByClient); } @@ -191,53 +193,48 @@ namespace Multiplayer } const AZ::CVarFixedString remoteAddress = editorsv_serveraddr; - if (editorsv_launch && LocalHost == remoteAddress) + if (editorsv_launch) { + if (LocalHost != remoteAddress) + { + AZ_Warning( + "MultiplayerEditor", false, + "Launching EditorServer skipped because incompatible cvars. editorsv_launch=true, meaning you want to launch an editor-server on this machine, but the editorsv_serveraddr is %s instead of the local address (127.0.0.1)." + "Please either set editorsv_launch=false and keep the remote editor-server, or set editorsv_launch=true and editorsv_serveraddr=127.0.0.1.", + remoteAddress.c_str()) + return; + } + + // Begin listening so we know when the editor-server being ready for us + INetworkInterface* editorNetworkInterface = + AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpEditorInterfaceName)); + AZ_Assert(editorNetworkInterface, "MP Editor Network Interface was unregistered before Editor could connect."); + editorNetworkInterface->Listen(editorsv_port); + + // Launch the editor-server m_serverProcess = LaunchEditorServer(); } - - // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets - AZ::Interface::Get()->BuildSpawnablesList(); - - // Now that the server has launched, attempt to connect the NetworkInterface - INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpEditorInterfaceName)); - AZ_Assert(editorNetworkInterface, "MP Editor Network Interface was unregistered before Editor could connect."); - m_editorConnId = editorNetworkInterface->Connect( - AzNetworking::IpAddress(remoteAddress.c_str(), editorsv_port, AzNetworking::ProtocolType::Tcp)); - - if (m_editorConnId == AzNetworking::InvalidConnectionId) - { - AZ_Warning( - "MultiplayerEditor", false, - "Could not connect to server targeted by Editor. If using a local server, check that it's built and editorsv_launch is true."); - return; - } - - // Read the buffer into EditorServerInit packets until we've flushed the whole thing - byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); - - while (byteStream.GetCurPos() < byteStream.GetLength()) + else { - MultiplayerEditorPackets::EditorServerInit packet; - auto& outBuffer = packet.ModifyAssetData(); - - // Size the packet's buffer appropriately - size_t readSize = outBuffer.GetCapacity(); - size_t byteStreamSize = byteStream.GetLength() - byteStream.GetCurPos(); - if (byteStreamSize < readSize) + // Editorsv_launch=false, so we're expecting an editor-server already exists. + // Connect to the editor-server and then send the EditorServerInit packet. + INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpEditorInterfaceName)); + AZ_Assert(editorNetworkInterface, "MP Editor Network Interface was unregistered before Editor could connect.") + + m_editorConnId = editorNetworkInterface->Connect(AzNetworking::IpAddress(remoteAddress.c_str(), editorsv_port, AzNetworking::ProtocolType::Tcp)); + + if (m_editorConnId == AzNetworking::InvalidConnectionId) { - readSize = byteStreamSize; + AZ_Warning( + "MultiplayerEditor", false, + "Editor game-mode multiplayer failed! Could not connect to an editor-server. editorsv_launch is false so we're assuming you're running your own editor-server at editorsv_serveraddr(%s) on editorsv_port(%i)." + "Either set editorsv_launch=true so the editor launches an editor-server for you, or launch your own editor-server by hand before entering game-mode. Remember editor-servers must use editorsv_isDedicated=true.", + remoteAddress.c_str(), + static_cast < uint16_t>(editorsv_port)) + return; } - outBuffer.Resize(readSize); - byteStream.Read(readSize, outBuffer.GetBuffer()); - - // If we've run out of buffer, mark that we're done - if (byteStream.GetCurPos() == byteStream.GetLength()) - { - packet.SetLastUpdate(true); - } - editorNetworkInterface->SendReliablePacket(m_editorConnId, packet); + SendEditorServerInitPacket(editorNetworkInterface->GetConnectionSet().GetConnection(m_editorConnId)); } } } @@ -253,4 +250,64 @@ namespace Multiplayer // but since we're in Editor, we're already in the level. AZ::Interface::Get()->SendReadyForEntityUpdates(true); } + + void MultiplayerEditorSystemComponent::SendEditorServerInitPacket(AzNetworking::IConnection* connection) + { + const auto prefabEditorEntityOwnershipInterface = AZ::Interface::Get(); + if (!prefabEditorEntityOwnershipInterface) + { + AZ_Error("MultiplayerEditor", prefabEditorEntityOwnershipInterface != nullptr, "PrefabEditorEntityOwnershipInterface unavailable") + return; + } + + const AZStd::vector>& assetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData(); + + AZStd::vector buffer; + AZ::IO::ByteContainerStream byteStream(&buffer); + + // Serialize Asset information and AssetData into a potentially large buffer + for (const auto& asset : assetData) + { + AZ::Data::AssetId assetId = asset.GetId(); + AZStd::string assetHint = asset.GetHint(); + auto hintSize = aznumeric_cast(assetHint.size()); + + byteStream.Write(sizeof(AZ::Data::AssetId), reinterpret_cast(&assetId)); + byteStream.Write(sizeof(uint32_t), reinterpret_cast(&hintSize)); + byteStream.Write(assetHint.size(), assetHint.data()); + AZ::Utils::SaveObjectToStream(byteStream, AZ::DataStream::ST_BINARY, asset.GetData(), asset.GetData()->GetType()); + } + + // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets + AZ::Interface::Get()->BuildSpawnablesList(); + + // Read the buffer into EditorServerInit packets until we've flushed the whole thing + byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); + + while (byteStream.GetCurPos() < byteStream.GetLength()) + { + MultiplayerEditorPackets::EditorServerInit editorServerInitPacket; + auto& outBuffer = editorServerInitPacket.ModifyAssetData(); + + // Size the packet's buffer appropriately + size_t readSize = outBuffer.GetCapacity(); + const size_t byteStreamSize = byteStream.GetLength() - byteStream.GetCurPos(); + if (byteStreamSize < readSize) + { + readSize = byteStreamSize; + } + + outBuffer.Resize(readSize); + byteStream.Read(readSize, outBuffer.GetBuffer()); + + // If we've run out of buffer, mark that we're done + if (byteStream.GetCurPos() == byteStream.GetLength()) + { + editorServerInitPacket.SetLastUpdate(true); + } + + connection->SendReliablePacket(editorServerInitPacket); + } + } + } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h index 4e4c6b677f..5d1d2fea24 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.h @@ -9,7 +9,7 @@ #pragma once #include - +#include #include #include @@ -35,6 +35,7 @@ namespace Multiplayer , private AzFramework::GameEntityContextEventBus::Handler , private AzToolsFramework::EditorEvents::Bus::Handler , private IEditorNotifyListener + , private MultiplayerEditorServerRequestBus::Handler { public: AZ_COMPONENT(MultiplayerEditorSystemComponent, "{9F335CC0-5574-4AD3-A2D8-2FAEF356946C}"); @@ -73,6 +74,11 @@ namespace Multiplayer void OnGameEntitiesReset() override; //! @} + //! MultiplayerEditorServerRequestBus::Handler + //! @{ + void SendEditorServerInitPacket(AzNetworking::IConnection* connection) override; + //! @} + IEditor* m_editor = nullptr; AzFramework::ProcessWatcher* m_serverProcess = nullptr; AzNetworking::ConnectionId m_editorConnId; diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index f16483e663..292fba5624 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -13,6 +13,7 @@ set(FILES Include/Multiplayer/MultiplayerConstants.h Include/Multiplayer/MultiplayerStats.h Include/Multiplayer/MultiplayerTypes.h + Include/Multiplayer/MultiplayerEditorServerBus.h Include/Multiplayer/Components/LocalPredictionPlayerInputComponent.h Include/Multiplayer/Components/MultiplayerComponent.h Include/Multiplayer/Components/MultiplayerComponentRegistry.h From 5ade5291b02555b07bc828f00d2d7c1b74f09070 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 22 Oct 2021 17:13:44 -0700 Subject: [PATCH 019/200] Minor code comment edit Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 0878dbd8cb..6213e8d725 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -205,7 +205,8 @@ namespace Multiplayer return; } - // Begin listening so we know when the editor-server being ready for us + // Begin listening for MPEditor packets before we launch the editor-server. + // The editor-server will send us (the editor) an "EditorServerReadyForInit" packet to let us know it's ready to receive data. INetworkInterface* editorNetworkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpEditorInterfaceName)); AZ_Assert(editorNetworkInterface, "MP Editor Network Interface was unregistered before Editor could connect."); @@ -227,7 +228,7 @@ namespace Multiplayer { AZ_Warning( "MultiplayerEditor", false, - "Editor game-mode multiplayer failed! Could not connect to an editor-server. editorsv_launch is false so we're assuming you're running your own editor-server at editorsv_serveraddr(%s) on editorsv_port(%i)." + "Editor multiplayer game-mode failed! Could not connect to an editor-server. editorsv_launch is false so we're assuming you're running your own editor-server at editorsv_serveraddr(%s) on editorsv_port(%i)." "Either set editorsv_launch=true so the editor launches an editor-server for you, or launch your own editor-server by hand before entering game-mode. Remember editor-servers must use editorsv_isDedicated=true.", remoteAddress.c_str(), static_cast < uint16_t>(editorsv_port)) From 3d7346ac3266c6cce5d980f5a3022be0c6a29f53 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sat, 23 Oct 2021 16:02:41 -0700 Subject: [PATCH 020/200] increasing multiplayer is-in-game timeout, going to try this on Jenkin. Maybe AssetProcessor isn't finished and thats why its failing? Signed-off-by: Gene Walters --- .../EditorPythonTestTools/editor_python_test_tools/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1928f2342b..713eb74f8c 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -90,7 +90,7 @@ class TestHelper: found_unexpected_lines = [x for x in found_lines if unexpected_line in x] Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) - TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30.0) + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30*60.0) # @todo delete! debugging Jenkins Report.info("PRINTING THE ENTIRE SERVER LOG!") From 8380c5ff246c2c995e17b74a252cd0dd7f4e0bba Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sat, 23 Oct 2021 16:41:30 -0700 Subject: [PATCH 021/200] Lowering timeout so pytest doesnt abort, but still get mode time to read the server logs Signed-off-by: Gene Walters --- .../EditorPythonTestTools/editor_python_test_tools/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 713eb74f8c..4d57f80bfb 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -90,7 +90,7 @@ class TestHelper: found_unexpected_lines = [x for x in found_lines if unexpected_line in x] Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) - TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30*60.0) + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 90.0) # @todo delete! debugging Jenkins Report.info("PRINTING THE ENTIRE SERVER LOG!") From ea4a898d74a90da50af6653b6a8384d03ba524c9 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sat, 23 Oct 2021 19:30:51 -0700 Subject: [PATCH 022/200] Minor, adding some null checks Signed-off-by: Gene Walters --- .../Source/Editor/MultiplayerEditorSystemComponent.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 64e8b96e9f..7d4a58dbeb 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -52,7 +52,13 @@ namespace Multiplayer bool PyIsInGameMode() { // If the network entity manager is tracking at least 1 entity then the editor has connected and the autonomous player exists and is being replicated. - return AZ::Interface::Get()->GetEntityCount() > 0; + if (const INetworkEntityManager* networkEntityManager = AZ::Interface::Get()) + { + return networkEntityManager->GetEntityCount() > 0; + } + + AZ_Warning("MultiplayerEditorSystemComponent", false, "PyIsInGameMode returning false; no NetworkEntityManager has not been created yet."); + return false; } void PythonEditorFuncs::Reflect(AZ::ReflectContext* context) From 7de5c17fb679d222c80451ec048904fc365bbfe7 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sun, 24 Oct 2021 23:07:58 -0700 Subject: [PATCH 023/200] The editor might not be the connector so make sure to connect to the actual MP simulation even if the editor isn't the editor-server connect (if editorsv_launch=true then the editor-server will connect to the editor) Signed-off-by: Gene Walters --- .../Editor/MultiplayerEditorConnection.cpp | 26 ++++++++----------- .../MultiplayerEditorSystemComponent.cpp | 2 +- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index fb0b86af6a..0c226445a4 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -47,7 +46,7 @@ namespace Multiplayer ConnectionId editorServerToEditorConnectionId = m_networkEditorInterface->Connect(IpAddress(LocalHost.data(), editorsv_port, ProtocolType::Tcp)); // If there wasn't an Editor waiting for this server to start, then assume this is an editor-server launched by hand... listen and wait for the editor to request a connection - if (editorServerToEditorConnectionId == AzNetworking::InvalidConnectionId) + if (editorServerToEditorConnectionId == InvalidConnectionId) { m_networkEditorInterface->Listen(editorsv_port); } @@ -154,21 +153,18 @@ namespace Multiplayer [[maybe_unused]] MultiplayerEditorPackets::EditorServerReady& packet ) { - if (connection->GetConnectionRole() == ConnectionRole::Connector) - { - // Receiving this packet means Editor sync is done, disconnect - connection->Disconnect(AzNetworking::DisconnectReason::TerminatedByClient, AzNetworking::TerminationEndpoint::Local); + // Receiving this packet means Editor sync is done, disconnect + connection->Disconnect(AzNetworking::DisconnectReason::TerminatedByClient, AzNetworking::TerminationEndpoint::Local); - if (auto console = AZ::Interface::Get(); console) + if (const auto console = AZ::Interface::Get()) + { + AZ::CVarFixedString remoteAddress; + uint16_t remotePort; + if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound && + console->GetCvarValue("sv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound) { - AZ::CVarFixedString remoteAddress; - uint16_t remotePort; - if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound && - console->GetCvarValue("sv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound) - { - // Connect the Editor to the editor server for Multiplayer simulation - AZ::Interface::Get()->Connect(remoteAddress.c_str(), remotePort); - } + // Connect the Editor to the editor server for Multiplayer simulation + AZ::Interface::Get()->Connect(remoteAddress.c_str(), remotePort); } } return true; diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 6213e8d725..469bfa21aa 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -199,7 +199,7 @@ namespace Multiplayer { AZ_Warning( "MultiplayerEditor", false, - "Launching EditorServer skipped because incompatible cvars. editorsv_launch=true, meaning you want to launch an editor-server on this machine, but the editorsv_serveraddr is %s instead of the local address (127.0.0.1)." + "Launching EditorServer skipped because incompatible cvars. editorsv_launch=true, meaning you want to launch an editor-server on this machine, but the editorsv_serveraddr is %s instead of the local address (127.0.0.1). " "Please either set editorsv_launch=false and keep the remote editor-server, or set editorsv_launch=true and editorsv_serveraddr=127.0.0.1.", remoteAddress.c_str()) return; From 2f651c05c893d8e13e220fcb2d1ecd35a696fd36 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Sun, 24 Oct 2021 23:28:10 -0700 Subject: [PATCH 024/200] Python passes lower-case net-player-prefab path. Signed-off-by: Gene Walters --- .../Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py index fe727b2506..7b56213313 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_AutoComponent_NetworkInput.py @@ -80,7 +80,7 @@ def Multiplayer_AutoComponent_NetworkInput(): with Tracer() as section_tracer: # 2) Enter game mode - helper.multiplayer_enter_game_mode(Tests.enter_game_mode, player_prefab_path) + 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) From 1f2eaface9a084a6fb183081443d1534c6f88b19 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:45:12 -0700 Subject: [PATCH 025/200] [profiler_capture_api] merging overlapping profiler EBuses into AzCore Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/AzCore/Debug/ProfilerBus.h | 34 +++++---- .../AzCore/Debug/ProfilerReflection.cpp | 70 +++++++++++++++++++ .../AzCore/AzCore/Debug/ProfilerReflection.h | 19 +++++ .../AzCore/Script/ScriptSystemComponent.cpp | 2 + .../AzCore/AzCore/azcore_files.cmake | 2 + .../Code/Include/Profiler/ProfilerBus.h | 59 ---------------- .../Profiler/Code/Source/ImGuiCpuProfiler.cpp | 47 +++++++------ Gems/Profiler/Code/Source/ImGuiCpuProfiler.h | 3 + .../Code/Source/ProfilerSystemComponent.cpp | 70 ++++--------------- .../Code/Source/ProfilerSystemComponent.h | 14 ++-- Gems/Profiler/Code/profiler_files.cmake | 1 - 11 files changed, 165 insertions(+), 156 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp create mode 100644 Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.h delete mode 100644 Gems/Profiler/Code/Include/Profiler/ProfilerBus.h diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h index 1537be3b81..31eb0c9160 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h @@ -9,6 +9,8 @@ #pragma once #include +#include +#include namespace AZ { @@ -23,17 +25,13 @@ 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 */ @@ -41,14 +39,26 @@ namespace AZ : public AZ::EBusTraits { public: + // EBusTraits overrides + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + // Allow multiple threads to concurrently make requests using MutexType = AZStd::mutex; 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(const AZStd::string& outputFilePath) = 0; + virtual bool EndCapture() = 0; }; using ProfilerRequestBus = AZ::EBus; - } -} + } // 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..72ad4b735b --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp @@ -0,0 +1,70 @@ +/* + * 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 + +namespace AZ::Debug +{ + 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::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "debug") + ->Handler(); + } + } + }; + + void ProfilerReflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + if (AZ::EditContext* ec = serialize->GetEditContext()) + { + ProfilerNotificationBusHandler::Reflect(context); + } + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("ProfilerRequestBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "debug") + + ->Event("IsActive", &ProfilerRequestBus::Events::IsActive) + ->Event("SetActive", &ProfilerRequestBus::Events::SetActive) + + ->Event("CaptureFrame", &ProfilerRequestBus::Events::CaptureFrame) + + ->Event("StartCapture", &ProfilerRequestBus::Events::StartCapture) + ->Event("EndCapture", &ProfilerRequestBus::Events::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/Script/ScriptSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp index a83232c8cb..3fa20cb682 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 @@ -925,6 +926,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/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 41229429f2..bb824a6436 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -106,6 +106,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 diff --git a/Gems/Profiler/Code/Include/Profiler/ProfilerBus.h b/Gems/Profiler/Code/Include/Profiler/ProfilerBus.h deleted file mode 100644 index 22352185d3..0000000000 --- a/Gems/Profiler/Code/Include/Profiler/ProfilerBus.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include -#include -#include - -namespace Profiler -{ - class ProfilerRequests - { - public: - AZ_RTTI(ProfilerRequests, "{3757c4e5-1941-457c-85ae-16305e17a4c6}"); - virtual ~ProfilerRequests() = default; - - //! Enable/Disable the CpuProfiler - virtual void SetProfilerEnabled(bool enabled) = 0; - - //! Dump a single frame of Cpu profiling data - virtual bool CaptureCpuProfilingStatistics(const AZStd::string& outputFilePath) = 0; - - //! Start a multiframe capture of CPU profiling data. - virtual bool BeginContinuousCpuProfilingCapture() = 0; - - //! End and dump an in-progress continuous capture. - virtual bool EndContinuousCpuProfilingCapture(const AZStd::string& outputFilePath) = 0; - }; - - class ProfilerBusTraits - : public AZ::EBusTraits - { - public: - // EBusTraits overrides - static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - }; - - class ProfilerNotifications - : public AZ::EBusTraits - { - public: - virtual ~ProfilerNotifications() = default; - - //! Notify when the current CpuProfilingStatistics 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 OnCaptureCpuProfilingStatisticsFinished(bool result, const AZStd::string& info) = 0; - }; - - using ProfilerInterface = AZ::Interface; - using ProfilerRequestBus = AZ::EBus; - using ProfilerNotificationBus = AZ::EBus; -} // namespace Profiler diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 3f364f99e0..0320020e86 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -10,9 +10,9 @@ #include -#include #include +#include #include #include #include @@ -156,16 +156,10 @@ namespace Profiler if (m_captureToFile) { - AZStd::string timeString; - AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - - const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_single_%s.json", defaultSaveLocation, timeString.c_str()); - - char resolvedPath[AZ::IO::MaxPathLength]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); - m_lastCapturedFilePath = resolvedPath; - - ProfilerRequestBus::Broadcast(&ProfilerRequestBus::Events::CaptureCpuProfilingStatistics, frameDataFilePath); + AZ::Debug::ProfilerRequestBus::Broadcast( + &AZ::Debug::ProfilerRequestBus::Events::CaptureFrame, + GenerateOutputFile("single") + ); } m_captureToFile = false; @@ -208,22 +202,15 @@ namespace Profiler { if (isInProgress) { - AZStd::string timeString; - AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - - const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_multi_%s.json", defaultSaveLocation, timeString.c_str()); - - char resolvedPath[AZ::IO::MaxPathLength]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); - m_lastCapturedFilePath = resolvedPath; - - ProfilerRequestBus::Broadcast(&ProfilerRequestBus::Events::EndContinuousCpuProfilingCapture, frameDataFilePath); - + AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::EndCapture); m_paused = true; } else { - ProfilerRequestBus::Broadcast(&ProfilerRequestBus::Events::BeginContinuousCpuProfilingCapture); + AZ::Debug::ProfilerRequestBus::Broadcast( + &AZ::Debug::ProfilerRequestBus::Events::StartCapture, + GenerateOutputFile("multi") + ); } } @@ -418,6 +405,20 @@ namespace Profiler ImGui::End(); } + AZStd::string ImGuiCpuProfiler::GenerateOutputFile(const char* nameHint) + { + AZStd::string timeString; + AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); + + const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_%s_%s.json", defaultSaveLocation, nameHint, timeString.c_str()); + + char resolvedPath[AZ::IO::MaxPathLength]; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); + m_lastCapturedFilePath = resolvedPath; + + return frameDataFilePath; + } + void ImGuiCpuProfiler::LoadFile() { const AZ::IO::Path& pathToLoad = m_cachedCapturePaths[m_currentFileIndex]; diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h index 2c6a3e470a..f074a9974f 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h @@ -107,6 +107,9 @@ namespace Profiler //! Draws the statistical view of the CPU profiling data. void DrawStatisticsView(); + //! Generates the full output timestamped file path based on nameHint + AZStd::string GenerateOutputFile(const char* nameHint); + //! Callback invoked when the "Load File" button is pressed in the file picker. void LoadFile(); diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp index bc51ffd0a7..f37aa702c1 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp @@ -51,32 +51,6 @@ namespace Profiler int m_framesLeft{ 0 }; }; - class ProfilerNotificationBusHandler final - : public ProfilerNotificationBus::Handler - , public AZ::BehaviorEBusHandler - { - public: - AZ_EBUS_BEHAVIOR_BINDER(ProfilerNotificationBusHandler, "{44161459-B816-4876-95A4-BA16DEC767D6}", AZ::SystemAllocator, - OnCaptureCpuProfilingStatisticsFinished - ); - - void OnCaptureCpuProfilingStatisticsFinished(bool result, const AZStd::string& info) override - { - Call(FN_OnCaptureCpuProfilingStatisticsFinished, result, info); - } - - static void Reflect(AZ::ReflectContext* context) - { - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->EBus("ProfilerNotificationBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Module, "profiler") - ->Handler(); - } - } - }; - bool SerializeCpuProfilingData(const AZStd::ring_buffer& data, AZStd::string outputFilePath, bool wasEnabled) { AZ_TracePrintf("ProfilerSystemComponent", "Beginning serialization of %zu frames of profiling data\n", data.size()); @@ -107,8 +81,8 @@ namespace Profiler CpuProfiler::Get()->SetProfilerEnabled(false); } - // Notify listeners that the pass' PipelineStatistics queries capture has finished. - ProfilerNotificationBus::Broadcast(&ProfilerNotificationBus::Events::OnCaptureCpuProfilingStatisticsFinished, + // Notify listeners that the profiler capture has finished. + AZ::Debug::ProfilerNotificationBus::Broadcast(&AZ::Debug::ProfilerNotificationBus::Events::OnCaptureFinished, saveResult.IsSuccess(), captureInfo); @@ -128,21 +102,9 @@ namespace Profiler ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) ->Attribute(AZ::Edit::Attributes::AutoExpand, true); - - ProfilerNotificationBusHandler::Reflect(context); } } - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->EBus("ProfilerRequestBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Module, "profiler") - ->Event("CaptureCpuProfilingStatistics", &ProfilerRequestBus::Events::CaptureCpuProfilingStatistics); - - ProfilerNotificationBusHandler::Reflect(context); - } - CpuProfilingStatisticsSerializer::Reflect(context); } @@ -166,23 +128,15 @@ namespace Profiler ProfilerSystemComponent::ProfilerSystemComponent() { - if (ProfilerInterface::Get() == nullptr) - { - ProfilerInterface::Register(this); - } } ProfilerSystemComponent::~ProfilerSystemComponent() { - if (ProfilerInterface::Get() == this) - { - ProfilerInterface::Unregister(this); - } } void ProfilerSystemComponent::Activate() { - ProfilerRequestBus::Handler::BusConnect(); + AZ::Debug::ProfilerRequestBus::Handler::BusConnect(); m_cpuProfiler.Init(); } @@ -191,7 +145,7 @@ namespace Profiler { m_cpuProfiler.Shutdown(); - ProfilerRequestBus::Handler::BusDisconnect(); + AZ::Debug::ProfilerRequestBus::Handler::BusDisconnect(); // Block deactivation until the IO thread has finished serializing the CPU data if (m_cpuDataSerializationThread.joinable()) @@ -200,12 +154,17 @@ namespace Profiler } } - void ProfilerSystemComponent::SetProfilerEnabled(bool enabled) + bool ProfilerSystemComponent::IsActive() const + { + return m_cpuProfiler.IsProfilerEnabled(); + } + + void ProfilerSystemComponent::SetActive(bool enabled) { m_cpuProfiler.SetProfilerEnabled(enabled); } - bool ProfilerSystemComponent::CaptureCpuProfilingStatistics(const AZStd::string& outputFilePath) + bool ProfilerSystemComponent::CaptureFrame(const AZStd::string& outputFilePath) { bool expected = false; if (!m_cpuCaptureInProgress.compare_exchange_strong(expected, true)) @@ -236,12 +195,13 @@ namespace Profiler return true; } - bool ProfilerSystemComponent::BeginContinuousCpuProfilingCapture() + bool ProfilerSystemComponent::StartCapture(const AZStd::string& outputFilePath) { + m_captureFile = outputFilePath; return m_cpuProfiler.BeginContinuousCapture(); } - bool ProfilerSystemComponent::EndContinuousCpuProfilingCapture(const AZStd::string& outputFilePath) + bool ProfilerSystemComponent::EndCapture() { bool expected = false; if (!m_cpuDataSerializationInProgress.compare_exchange_strong(expected, true)) @@ -263,7 +223,7 @@ namespace Profiler // cpuProfilingData could be 1GB+ once saved, so use an IO thread to write it to disk. auto threadIoFunction = - [data = AZStd::move(captureResult), filePath = AZStd::string(outputFilePath), &flag = m_cpuDataSerializationInProgress]() + [data = AZStd::move(captureResult), filePath = m_captureFile, &flag = m_cpuDataSerializationInProgress]() { SerializeCpuProfilingData(data, filePath, true); flag.store(false); diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h index 76121be04f..534e7d8386 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h @@ -8,17 +8,17 @@ #pragma once -#include #include #include +#include #include namespace Profiler { class ProfilerSystemComponent : public AZ::Component - , protected ProfilerRequestBus::Handler + , protected AZ::Debug::ProfilerRequestBus::Handler { public: AZ_COMPONENT(ProfilerSystemComponent, "{3f52c1d7-d920-4781-8ed7-88077ec4f305}"); @@ -39,10 +39,11 @@ namespace Profiler void Deactivate() override; // ProfilerRequestBus interface implementation - void SetProfilerEnabled(bool enabled) override; - bool CaptureCpuProfilingStatistics(const AZStd::string& outputFilePath) override; - bool BeginContinuousCpuProfilingCapture() override; - bool EndContinuousCpuProfilingCapture(const AZStd::string& outputFilePath) override; + bool IsActive() const override; + void SetActive(bool active) override; + bool CaptureFrame(const AZStd::string& outputFilePath) override; + bool StartCapture(const AZStd::string& outputFilePath) override; + bool EndCapture() override; AZStd::thread m_cpuDataSerializationThread; @@ -51,6 +52,7 @@ namespace Profiler AZStd::atomic_bool m_cpuCaptureInProgress{ false }; CpuProfilerImpl m_cpuProfiler; + AZStd::string m_captureFile; }; } // namespace Profiler diff --git a/Gems/Profiler/Code/profiler_files.cmake b/Gems/Profiler/Code/profiler_files.cmake index 51ceb00139..ebbca1cd78 100644 --- a/Gems/Profiler/Code/profiler_files.cmake +++ b/Gems/Profiler/Code/profiler_files.cmake @@ -7,7 +7,6 @@ # set(FILES - Include/Profiler/ProfilerBus.h Include/Profiler/ProfilerImGuiBus.h Source/CpuProfiler.h Source/CpuProfilerImpl.cpp From 6ddfb6500f0467a9887168d2b45382f8c0fda178 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:45:58 -0700 Subject: [PATCH 026/200] [profiler_capture_api] fixed ambiguous LogLevel type in some unity file scenarios Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/Trace.cpp | 25 ++-- .../WinAPI/AzCore/Debug/Trace_WinAPI.cpp | 139 +++++++++--------- 2 files changed, 78 insertions(+), 86 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp index 357149d096..1dd9d0f0f9 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp @@ -27,26 +27,21 @@ #include #include -namespace AZ +namespace AZ::Debug { - namespace Debug - { - struct StackFrame; + struct StackFrame; - namespace Platform - { + namespace Platform + { #if defined(AZ_ENABLE_DEBUG_TOOLS) - bool AttachDebugger(); - bool IsDebuggerPresent(); - void HandleExceptions(bool isEnabled); - void DebugBreak(); + bool AttachDebugger(); + bool IsDebuggerPresent(); + void HandleExceptions(bool isEnabled); + void DebugBreak(); #endif - void Terminate(int exitCode); - } + void Terminate(int exitCode); } - using namespace AZ::Debug; - namespace DebugInternal { // other threads can trigger fatals and errors, but the same thread should not, to avoid stack overflow. @@ -616,4 +611,4 @@ namespace AZ val.Set(level); } } -} // namspace AZ +} // namspace AZ::Debug 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..9b78da222c 100644 --- a/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp +++ b/Code/Framework/AzCore/Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp @@ -17,7 +17,7 @@ #include -namespace AZ +namespace AZ::Debug { #if defined(AZ_ENABLE_DEBUG_TOOLS) LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo); @@ -26,94 +26,91 @@ namespace AZ constexpr int g_maxMessageLength = 4096; - namespace Debug + namespace Platform { - namespace Platform - { #if defined(AZ_ENABLE_DEBUG_TOOLS) - bool IsDebuggerPresent() + bool IsDebuggerPresent() + { + return ::IsDebuggerPresent() ? true : false; + } + + void HandleExceptions(bool isEnabled) + { + if (isEnabled) { - return ::IsDebuggerPresent() ? true : false; + g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler); } - - void HandleExceptions(bool isEnabled) + else { - if (isEnabled) - { - g_previousExceptionHandler = ::SetUnhandledExceptionFilter(&ExceptionHandler); - } - else - { - ::SetUnhandledExceptionFilter(g_previousExceptionHandler); - g_previousExceptionHandler = NULL; - } + ::SetUnhandledExceptionFilter(g_previousExceptionHandler); + g_previousExceptionHandler = NULL; } + } - bool AttachDebugger() + bool AttachDebugger() + { + if (IsDebuggerPresent()) { - if (IsDebuggerPresent()) - { - return true; - } - - // Launch vsjitdebugger.exe, this app is always present in System32 folder - // with an installation of any version of visual studio. - // It will open a debugging dialog asking the user what debugger to use - - STARTUPINFOW startupInfo = {0}; - startupInfo.cb = sizeof(startupInfo); - PROCESS_INFORMATION processInfo = {0}; - - wchar_t cmdline[MAX_PATH]; - swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId()); - bool success = ::CreateProcessW( - NULL, // No module name (use command line) - cmdline, // Command line - NULL, // Process handle not inheritable - NULL, // Thread handle not inheritable - FALSE, // No handle inheritance - 0, // No creation flags - NULL, // Use parent's environment block - NULL, // Use parent's starting directory - &startupInfo, // Pointer to STARTUPINFO structure - &processInfo); // Pointer to PROCESS_INFORMATION structure - - if (success) - { - ::WaitForSingleObject(processInfo.hProcess, INFINITE); - ::CloseHandle(processInfo.hProcess); - ::CloseHandle(processInfo.hThread); - return true; - } - return false; + return true; } - void DebugBreak() + // Launch vsjitdebugger.exe, this app is always present in System32 folder + // with an installation of any version of visual studio. + // It will open a debugging dialog asking the user what debugger to use + + STARTUPINFOW startupInfo = {0}; + startupInfo.cb = sizeof(startupInfo); + PROCESS_INFORMATION processInfo = {0}; + + wchar_t cmdline[MAX_PATH]; + swprintf_s(cmdline, L"vsjitdebugger.exe -p %li", ::GetCurrentProcessId()); + bool success = ::CreateProcessW( + NULL, // No module name (use command line) + cmdline, // Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + FALSE, // No handle inheritance + 0, // No creation flags + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &startupInfo, // Pointer to STARTUPINFO structure + &processInfo); // Pointer to PROCESS_INFORMATION structure + + if (success) { - __debugbreak(); + ::WaitForSingleObject(processInfo.hProcess, INFINITE); + ::CloseHandle(processInfo.hProcess); + ::CloseHandle(processInfo.hThread); + return true; } + return false; + } + + void DebugBreak() + { + __debugbreak(); + } #endif // AZ_ENABLE_DEBUG_TOOLS - void Terminate(int exitCode) - { - TerminateProcess(GetCurrentProcess(), exitCode); - } + void Terminate(int exitCode) + { + TerminateProcess(GetCurrentProcess(), exitCode); + } - void OutputToDebugger([[maybe_unused]] const char* window, const char* message) + void OutputToDebugger([[maybe_unused]] const char* window, const char* message) + { + AZStd::fixed_wstring tmpW; + if(window) { - AZStd::fixed_wstring tmpW; - if(window) - { - AZStd::to_wstring(tmpW, window); - tmpW += L": "; - OutputDebugStringW(tmpW.c_str()); - tmpW.clear(); - } - AZStd::to_wstring(tmpW, message); + AZStd::to_wstring(tmpW, window); + tmpW += L": "; OutputDebugStringW(tmpW.c_str()); + tmpW.clear(); } + AZStd::to_wstring(tmpW, message); + OutputDebugStringW(tmpW.c_str()); } - } + } // namespace Platform #if defined(AZ_ENABLE_DEBUG_TOOLS) @@ -211,4 +208,4 @@ namespace AZ } #endif -} +} // namspace AZ::Debug From 471436b0fc731f185a4cc2f2b359f152bc432e6e Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:48:00 -0700 Subject: [PATCH 027/200] [profiler_capture_api] added cvar/console access for profiler capture Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/AzCore/Debug/Profiler.cpp | 40 +++++++++++++++++++ .../Profiler/Code/Source/ImGuiCpuProfiler.cpp | 16 ++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp index 0bb92b923d..4abda46214 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp @@ -7,4 +7,44 @@ */ #include +#include +#include +#include +namespace AZ::Debug +{ + AZ_CVAR(AZ::CVarFixedString, bg_profilerCaptureLocation, "@user@/Profiler", nullptr, ConsoleFunctorFlags::Null, + "Specify where to save profiler capture data"); + + AZStd::string GenerateOutputFile(const char* nameHint) + { + AZStd::string timeString; + AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); + + AZ::CVarFixedString captureOutput = static_cast(bg_profilerCaptureLocation); + + return AZStd::string::format("%s/capture_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); + } + + void ProfilerCaptureFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + AZStd::string captureFile = GenerateOutputFile("single"); + AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); + AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::CaptureFrame, captureFile); + } + AZ_CONSOLEFREEFUNC(ProfilerCaptureFrame, AZ::ConsoleFunctorFlags::DontReplicate, "Capture a single frame of profiling data"); + + void ProfilerStartCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + AZStd::string captureFile = GenerateOutputFile("multi"); + AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); + ProfilerRequestBus::Broadcast(&ProfilerRequestBus::Events::StartCapture, captureFile); + } + AZ_CONSOLEFREEFUNC(ProfilerStartCapture, AZ::ConsoleFunctorFlags::DontReplicate, "Start a multi-frame capture of profiling data"); + + void ProfilerEndCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::EndCapture); + } + AZ_CONSOLEFREEFUNC(ProfilerEndCapture, AZ::ConsoleFunctorFlags::DontReplicate, "End and dump an in-progress continuous capture"); +} // namespace AZ::Debug diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 0320020e86..52fe09f9e8 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -24,10 +25,13 @@ #include #include -namespace Profiler +namespace AZ::Debug { - static constexpr const char* defaultSaveLocation = "@user@/Profiler"; + AZ_CVAR_EXTERNED(AZ::CVarFixedString, bg_profilerCaptureLocation); +} +namespace Profiler +{ namespace CpuProfilerImGuiHelper { float TicksToMs(double ticks) @@ -222,8 +226,10 @@ namespace Profiler // Only update the cached file list when opened so that we aren't making IO calls on every frame. m_cachedCapturePaths.clear(); + AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); + auto* base = AZ::IO::FileIOBase::GetInstance(); - base->FindFiles(defaultSaveLocation, "*.json", + base->FindFiles(captureOutput.c_str(), "*.json", [&paths = m_cachedCapturePaths](const char* path) -> bool { auto foundPath = AZ::IO::Path(path); @@ -410,7 +416,9 @@ namespace Profiler AZStd::string timeString; AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_%s_%s.json", defaultSaveLocation, nameHint, timeString.c_str()); + AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); + + const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); char resolvedPath[AZ::IO::MaxPathLength]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); From fe071f0736bb3a18b96c5a3a40395ada21f10af6 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 25 Oct 2021 12:57:40 -0700 Subject: [PATCH 028/200] Adding warnings if MPEditorConnection cannot find certain cvars Signed-off-by: Gene Walters --- .../Editor/MultiplayerEditorConnection.cpp | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index 0c226445a4..22ff68f5e9 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -36,14 +36,16 @@ namespace Multiplayer if (editorsv_isDedicated) { uint16_t editorsv_port = DefaultServerEditorPort; - if (const auto console = AZ::Interface::Get()) - { - console->GetCvarValue("editorsv_port", editorsv_port); - } + const auto console = AZ::Interface::Get(); + + AZ_Warning( + "MultiplayerEditorConnection", console->GetCvarValue("editorsv_port", editorsv_port) == AZ::GetValueResult::Success, + "MultiplayerEditorConnection failed! Could not find the editorsv_port cvar; we may not be able to connect to the editor's port!") + AZ_Assert(m_networkEditorInterface, "MP Editor Network Interface was unregistered before Editor Server could start listening.") // Check if there's already an Editor out there waiting to connect - ConnectionId editorServerToEditorConnectionId = m_networkEditorInterface->Connect(IpAddress(LocalHost.data(), editorsv_port, ProtocolType::Tcp)); + const ConnectionId editorServerToEditorConnectionId = m_networkEditorInterface->Connect(IpAddress(LocalHost.data(), editorsv_port, ProtocolType::Tcp)); // If there wasn't an Editor waiting for this server to start, then assume this is an editor-server launched by hand... listen and wait for the editor to request a connection if (editorServerToEditorConnectionId == InvalidConnectionId) @@ -117,18 +119,17 @@ namespace Multiplayer // Load the level via the root spawnable that was registered const AZ::CVarFixedString loadLevelString = "LoadLevel Root.spawnable"; - AZ::Interface::Get()->PerformCommand(loadLevelString.c_str()); + const auto console = AZ::Interface::Get(); + console->PerformCommand(loadLevelString.c_str()); // Setup the normal multiplayer connection AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer); INetworkInterface* networkInterface = AZ::Interface::Get()->RetrieveNetworkInterface(AZ::Name(MpNetworkInterfaceName)); - uint16_t serverPort = DefaultServerPort; - if (auto console = AZ::Interface::Get(); console) - { - console->GetCvarValue("sv_port", serverPort); - } - networkInterface->Listen(serverPort); + uint16_t sv_port = DefaultServerPort; + AZ_Warning("MultiplayerEditorConnection", console->GetCvarValue("sv_port", sv_port) == AZ::GetValueResult::Success, + "MultiplayerEditorConnection::HandleRequest for EditorServerInit failed! Could not find the sv_port cvar; we won't be able to listen on the correct port for incoming network messages!") + networkInterface->Listen(sv_port); AZLOG_INFO("Editor Server completed asset receive, responding to Editor..."); return connection->SendReliablePacket(MultiplayerEditorPackets::EditorServerReady()); @@ -155,18 +156,23 @@ namespace Multiplayer { // Receiving this packet means Editor sync is done, disconnect connection->Disconnect(AzNetworking::DisconnectReason::TerminatedByClient, AzNetworking::TerminationEndpoint::Local); + const auto console = AZ::Interface::Get(); + AZ::CVarFixedString editorsv_serveraddr = AZ::CVarFixedString(LocalHost); + uint16_t sv_port = DefaultServerEditorPort; + + AZ_Warning( + "MultiplayerEditorConnection", console->GetCvarValue("sv_port", sv_port) == AZ::GetValueResult::Success, + "MultiplayerEditorConnection::HandleRequest for EditorServerReady failed! Could not find the sv_port cvar; we may not be able to " + "connect to the correct port for incoming network messages!") + + AZ_Warning( + "MultiplayerEditorConnection", console->GetCvarValue("editorsv_serveraddr", editorsv_serveraddr) == AZ::GetValueResult::Success, + "MultiplayerEditorConnection::HandleRequest for EditorServerReady failed! Could not find the editorsv_serveraddr cvar; we may not be able to " + "connect to the correct port for incoming network messages!") + + // Connect the Editor to the editor server for Multiplayer simulation + AZ::Interface::Get()->Connect(editorsv_serveraddr.c_str(), sv_port); - if (const auto console = AZ::Interface::Get()) - { - AZ::CVarFixedString remoteAddress; - uint16_t remotePort; - if (console->GetCvarValue("editorsv_serveraddr", remoteAddress) != AZ::GetValueResult::ConsoleVarNotFound && - console->GetCvarValue("sv_port", remotePort) != AZ::GetValueResult::ConsoleVarNotFound) - { - // Connect the Editor to the editor server for Multiplayer simulation - AZ::Interface::Get()->Connect(remoteAddress.c_str(), remotePort); - } - } return true; } @@ -197,13 +203,13 @@ namespace Multiplayer void MultiplayerEditorConnection::OnDisconnect([[maybe_unused]] AzNetworking::IConnection* connection, [[maybe_unused]] DisconnectReason reason, [[maybe_unused]] TerminationEndpoint endpoint) { - bool editorLaunch = false; - if (auto console = AZ::Interface::Get(); console) - { - console->GetCvarValue("editorsv_launch", editorLaunch); - } + const auto console = AZ::Interface::Get(); + bool editorsv_launch = false; + AZ_Warning( + "MultiplayerEditorConnection", console->GetCvarValue("editorsv_launch", editorsv_launch) == AZ::GetValueResult::Success, + "MultiplayerEditorConnection::OnDisconnect failed! Could not find the editorsv_launch cvar.") - if (editorsv_isDedicated && editorLaunch && m_networkEditorInterface->GetConnectionSet().GetConnectionCount() == 1) + if (editorsv_isDedicated && editorsv_launch && m_networkEditorInterface->GetConnectionSet().GetConnectionCount() == 1) { if (m_networkEditorInterface->GetPort() != 0) { From b4865e32f5f66b17fcd5d442409eb4562e7376c7 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 25 Oct 2021 13:04:20 -0700 Subject: [PATCH 029/200] Minor whitespace fix Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 469bfa21aa..dd9ffc29cb 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -280,7 +280,7 @@ namespace Multiplayer } // Spawnable library needs to be rebuilt since now we have newly registered in-memory spawnable assets - AZ::Interface::Get()->BuildSpawnablesList(); + AZ::Interface::Get()->BuildSpawnablesList(); // Read the buffer into EditorServerInit packets until we've flushed the whole thing byteStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN); From c6d3e7900cdb4971d8927fcf182740c744da870b Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 25 Oct 2021 15:51:12 -0700 Subject: [PATCH 030/200] [profiler_capture_api] updated ProfilerRequests::StartCapture signature as per PR feedback Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h | 2 +- Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp | 4 ++-- Gems/Profiler/Code/Source/ProfilerSystemComponent.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h index 31eb0c9160..89c59f01b5 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h @@ -56,7 +56,7 @@ namespace AZ virtual bool CaptureFrame(const AZStd::string& outputFilePath) = 0; //! Starting/ending a multi-frame capture of profiling data - virtual bool StartCapture(const AZStd::string& outputFilePath) = 0; + virtual bool StartCapture(AZStd::string outputFilePath) = 0; virtual bool EndCapture() = 0; }; using ProfilerRequestBus = AZ::EBus; diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp index f37aa702c1..09df0970b8 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp @@ -195,9 +195,9 @@ namespace Profiler return true; } - bool ProfilerSystemComponent::StartCapture(const AZStd::string& outputFilePath) + bool ProfilerSystemComponent::StartCapture(AZStd::string outputFilePath) { - m_captureFile = outputFilePath; + m_captureFile = AZStd::move(outputFilePath); return m_cpuProfiler.BeginContinuousCapture(); } diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h index 534e7d8386..000b11cfdf 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h @@ -42,7 +42,7 @@ namespace Profiler bool IsActive() const override; void SetActive(bool active) override; bool CaptureFrame(const AZStd::string& outputFilePath) override; - bool StartCapture(const AZStd::string& outputFilePath) override; + bool StartCapture(AZStd::string outputFilePath) override; bool EndCapture() override; From e38a44f0614925c8cc0830a156495479ead412a8 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 25 Oct 2021 18:18:12 -0700 Subject: [PATCH 031/200] [profiler_capture_api] minor memory usage rework pointed out in PR feedback Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp | 9 ++++----- Gems/Profiler/Code/Source/ImGuiCpuProfiler.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 52fe09f9e8..88b200c733 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -418,13 +418,12 @@ namespace Profiler AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); - const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); + const AZ::IO::FixedMaxPathString frameDataFilePath = + AZ::IO::FixedMaxPathString::format("%s/cpu_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); - char resolvedPath[AZ::IO::MaxPathLength]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); - m_lastCapturedFilePath = resolvedPath; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(m_lastCapturedFilePath, frameDataFilePath.c_str()); - return frameDataFilePath; + return m_lastCapturedFilePath.String(); } void ImGuiCpuProfiler::LoadFile() diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h index f074a9974f..2e01b8fd6b 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h @@ -217,7 +217,7 @@ namespace Profiler AZStd::vector m_cpuTimingStatisticsWhenPause; AZStd::sys_time_t m_frameToFrameTime{}; - AZStd::string m_lastCapturedFilePath; + AZ::IO::FixedMaxPath m_lastCapturedFilePath; bool m_showFilePicker = false; From dc336ffabaf6173e0659a8ddca879d548b12ba48 Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Tue, 26 Oct 2021 16:10:35 +0100 Subject: [PATCH 032/200] Added validation to net prefab processing to error if there are hierarchical entities without Net hierarchy components Signed-off-by: Sergey Pereslavtsev --- .../Pipeline/NetworkPrefabProcessor.cpp | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp index 27e59c0bf4..e9b7ace7c9 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include namespace Multiplayer { @@ -93,6 +95,41 @@ namespace Multiplayer }); } + static bool HasNetHierarchyComponents(const AZ::Entity* entity) + { + return (entity->FindComponent() != nullptr) + || (entity->FindComponent() != nullptr); + } + + static void ValidateNetHierarchies(const AZStd::vector& prefabNetEntities) + { + AZStd::unordered_map prefabEntitesMap; + + for (auto* entity : prefabNetEntities) + { + auto* entityTransform = entity->FindComponent(); + AZ_Assert(entityTransform, "Net entities have to have Transform Component"); + + AZ::EntityId parentId = entityTransform->GetParentId(); + + // The input entities array is sorted in the parent to children order, + // so we only need to check against already iterated entities + if (parentId.IsValid() && prefabEntitesMap.contains(parentId)) + { + AZ::Entity* parentEntity = prefabEntitesMap[parentId]; + bool parentValid = HasNetHierarchyComponents(parentEntity); + AZ_Error("NetworkPrefabProcessor", parentValid, "Parent Entity %s must have a Network Hierarchy component assigned", + parentEntity->GetName().c_str()); + + bool childValid = HasNetHierarchyComponents(entity); + AZ_Error("NetworkPrefabProcessor", childValid, "Child Entity %s must have a Network Hierarchy component assigned", + entity->GetName().c_str()); + } + + prefabEntitesMap[entity->GetId()] = entity; + } + } + void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab) { using namespace AzToolsFramework::Prefab; @@ -131,6 +168,9 @@ namespace Multiplayer // Sort the entities prior to processing. The entities will end up in the net spawnable in this order. SpawnableUtils::SortEntitiesByTransformHierarchy(prefabNetEntities); + // Here we validate the hierarchical net entities have one of Network Hierarchy components. + ValidateNetHierarchies(prefabNetEntities); + // Create an asset for our future network spawnable: this allows us to put references to the asset in the components AZ::Data::Asset networkSpawnableAsset; networkSpawnableAsset.Create(networkSpawnable->GetId()); From 57a69978b968dd40cc0062fabaf8141bfa9c6f2b Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Tue, 26 Oct 2021 12:15:30 -0700 Subject: [PATCH 033/200] [profiler_capture_api] replace profiler capture location cvar with setting registry entry Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/AzCore/Debug/Profiler.cpp | 22 +++++++++++++++---- .../AzCore/AzCore/Debug/ProfilerBus.h | 11 ++++++++++ .../Profiler/Code/Source/ImGuiCpuProfiler.cpp | 10 ++------- Registry/profiler.setreg | 15 +++++++++++++ 4 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 Registry/profiler.setreg diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp index 4abda46214..3b5033a07f 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp @@ -10,18 +10,16 @@ #include #include #include +#include namespace AZ::Debug { - AZ_CVAR(AZ::CVarFixedString, bg_profilerCaptureLocation, "@user@/Profiler", nullptr, ConsoleFunctorFlags::Null, - "Specify where to save profiler capture data"); - AZStd::string GenerateOutputFile(const char* nameHint) { AZStd::string timeString; AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - AZ::CVarFixedString captureOutput = static_cast(bg_profilerCaptureLocation); + AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation(); return AZStd::string::format("%s/capture_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); } @@ -47,4 +45,20 @@ namespace AZ::Debug AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::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 89c59f01b5..03a89b11f2 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h @@ -10,12 +10,19 @@ #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 */ @@ -60,5 +67,9 @@ namespace AZ virtual bool EndCapture() = 0; }; using ProfilerRequestBus = AZ::EBus; + + //! 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/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 88b200c733..fd19460153 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -12,7 +12,6 @@ #include -#include #include #include #include @@ -25,11 +24,6 @@ #include #include -namespace AZ::Debug -{ - AZ_CVAR_EXTERNED(AZ::CVarFixedString, bg_profilerCaptureLocation); -} - namespace Profiler { namespace CpuProfilerImGuiHelper @@ -226,7 +220,7 @@ namespace Profiler // Only update the cached file list when opened so that we aren't making IO calls on every frame. m_cachedCapturePaths.clear(); - AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); + AZ::IO::FixedMaxPathString captureOutput = AZ::Debug::GetProfilerCaptureLocation(); auto* base = AZ::IO::FileIOBase::GetInstance(); base->FindFiles(captureOutput.c_str(), "*.json", @@ -416,7 +410,7 @@ namespace Profiler AZStd::string timeString; AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); + AZ::IO::FixedMaxPathString captureOutput = AZ::Debug::GetProfilerCaptureLocation(); const AZ::IO::FixedMaxPathString frameDataFilePath = AZ::IO::FixedMaxPathString::format("%s/cpu_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); diff --git a/Registry/profiler.setreg b/Registry/profiler.setreg new file mode 100644 index 0000000000..a295b007e1 --- /dev/null +++ b/Registry/profiler.setreg @@ -0,0 +1,15 @@ +{ + "O3DE": + { + "AzCore": + { + "Debug": + { + "Profiler": + { + "CaptureLocation" : "@user@/Profiler" + } + } + } + } +} \ No newline at end of file From a2c42ab07281e1b7ef56496da12c70f86a59c782 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Tue, 26 Oct 2021 15:15:52 -0700 Subject: [PATCH 034/200] [profiler_capture_api] started migration of ProfilerRequests EBus to AZ::Interface Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/AzCore/Debug/Profiler.cpp | 23 +++++++++++------ .../AzCore/AzCore/Debug/ProfilerBus.h | 25 ++++++++++++------- .../AzCore/IO/Streamer/StreamerComponent.cpp | 5 +++- Gems/PhysX/Code/Source/Scene/PhysXScene.cpp | 5 +++- .../Profiler/Code/Source/ImGuiCpuProfiler.cpp | 13 +++------- .../Code/Source/ProfilerSystemComponent.cpp | 8 ++++++ 6 files changed, 52 insertions(+), 27 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp index 3b5033a07f..3b6b3b7e7a 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp @@ -26,23 +26,32 @@ namespace AZ::Debug void ProfilerCaptureFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { - AZStd::string captureFile = GenerateOutputFile("single"); - AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); - AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::CaptureFrame, captureFile); + 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) { - AZStd::string captureFile = GenerateOutputFile("multi"); - AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); - ProfilerRequestBus::Broadcast(&ProfilerRequestBus::Events::StartCapture, captureFile); + if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem) + { + AZStd::string captureFile = GenerateOutputFile("multi"); + AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); + profilerSystem->StartCapture(captureFile); + } } AZ_CONSOLEFREEFUNC(ProfilerStartCapture, AZ::ConsoleFunctorFlags::DontReplicate, "Start a multi-frame capture of profiling data"); void ProfilerEndCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { - AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::EndCapture); + if (auto profilerSystem = ProfilerSystemInterface::Get(); profilerSystem) + { + profilerSystem->EndCapture(); + } } AZ_CONSOLEFREEFUNC(ProfilerEndCapture, AZ::ConsoleFunctorFlags::DontReplicate, "End and dump an in-progress continuous capture"); diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h index 03a89b11f2..9194381e23 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h @@ -43,16 +43,9 @@ namespace AZ * ProfilerRequests provides an interface for making profiling system requests */ class ProfilerRequests - : public AZ::EBusTraits { public: - // EBusTraits overrides - static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - - // Allow multiple threads to concurrently make requests - using MutexType = AZStd::mutex; - + AZ_RTTI(ProfilerRequests, "{90AEC117-14C1-4BAE-9704-F916E49EF13F}"); virtual ~ProfilerRequests() = default; //! Getter/setter for the profiler active state @@ -66,7 +59,21 @@ namespace AZ virtual bool StartCapture(AZStd::string outputFilePath) = 0; virtual bool EndCapture() = 0; }; - using ProfilerRequestBus = AZ::EBus; + + class ProfilerRequestsTraits + : public AZ::EBusTraits + { + public: + // EBusTraits overrides + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + + // Allow multiple threads to concurrently make requests + using MutexType = AZStd::mutex; + }; + + using ProfilerSystemInterface = AZ::Interface; + using ProfilerRequestBus = AZ::EBus; //! 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 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/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp index 86e3ceb98f..22fc665eec 100644 --- a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp +++ b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp @@ -1175,7 +1175,10 @@ namespace PhysX using physx::PxGeometryType; bool isProfilingActive = false; - AZ::Debug::ProfilerRequestBus::BroadcastResult(isProfilingActive, &AZ::Debug::ProfilerRequests::IsActive); + if (auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); profilerSystem) + { + isProfilingActive = profilerSystem->IsActive(); + } if (!isProfilingActive) { diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index fd19460153..e1a734136b 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -154,10 +154,7 @@ namespace Profiler if (m_captureToFile) { - AZ::Debug::ProfilerRequestBus::Broadcast( - &AZ::Debug::ProfilerRequestBus::Events::CaptureFrame, - GenerateOutputFile("single") - ); + AZ::Debug::ProfilerSystemInterface::Get()->CaptureFrame(GenerateOutputFile("single")); } m_captureToFile = false; @@ -198,17 +195,15 @@ namespace Profiler bool isInProgress = CpuProfiler::Get()->IsContinuousCaptureInProgress(); if (ImGui::Button(isInProgress ? "End" : "Begin")) { + auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); if (isInProgress) { - AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::EndCapture); + profilerSystem->EndCapture(); m_paused = true; } else { - AZ::Debug::ProfilerRequestBus::Broadcast( - &AZ::Debug::ProfilerRequestBus::Events::StartCapture, - GenerateOutputFile("multi") - ); + profilerSystem->StartCapture(GenerateOutputFile("multi")); } } diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp index 09df0970b8..4deda64964 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp @@ -128,10 +128,18 @@ namespace Profiler ProfilerSystemComponent::ProfilerSystemComponent() { + if (AZ::Debug::ProfilerSystemInterface::Get() == nullptr) + { + AZ::Debug::ProfilerSystemInterface::Register(this); + } } ProfilerSystemComponent::~ProfilerSystemComponent() { + if (AZ::Debug::ProfilerSystemInterface::Get() == this) + { + AZ::Debug::ProfilerSystemInterface::Unregister(this); + } } void ProfilerSystemComponent::Activate() From 6d62dbba76fc9e184097a9c38a0da1599cb9efb2 Mon Sep 17 00:00:00 2001 From: jromnoa Date: Tue, 26 Oct 2021 18:51:09 -0700 Subject: [PATCH 035/200] fixes the basic level GPU test screenshot comparison failure Signed-off-by: jromnoa --- .../PythonTests/Atom/TestSuite_Main_GPU.py | 25 ++++----- .../Atom/atom_utils/atom_component_helper.py | 48 +++++++++++++++-- .../tests/hydra_GPUTest_BasicLevelSetup.py | 54 ++++++++++--------- 3 files changed, 85 insertions(+), 42 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 23fb249761..534b061b1c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -13,10 +13,10 @@ import zipfile import pytest import ly_test_tools.environment.file_system as file_system -from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator import editor_python_test_tools.hydra_test_utils as hydra +from .atom_utils.atom_component_helper import compare_screenshot_similarity, ImageComparisonTestFailure logger = logging.getLogger(__name__) DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' @@ -92,8 +92,6 @@ class TestAllComponentsIndepthTests(object): "Exited game mode" ] unexpected_lines = [ - "Trace::Assert", - "Trace::Error", "Traceback (most recent call last):", "Screenshot failed" ] @@ -111,10 +109,12 @@ class TestAllComponentsIndepthTests(object): null_renderer=False, ) - for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): - compare_screenshots(test_screenshot, golden_screenshot) - - create_screenshots_archive(screenshot_directory) + similarity_threshold = 0.99 + for test_screenshot, golden_image in zip(test_screenshots, golden_images): + screenshot_comparison_result = compare_screenshot_similarity( + test_screenshot, golden_image, similarity_threshold, True, screenshot_directory) + if screenshot_comparison_result != "Screenshots match": + raise Exception(f"Screenshot test failed: {screenshot_comparison_result}") @pytest.mark.test_case_id("C34525095") def test_LightComponent_ScreenshotMatchesGoldenImage( @@ -168,10 +168,12 @@ class TestAllComponentsIndepthTests(object): null_renderer=False, ) - for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images): - compare_screenshots(test_screenshot, golden_screenshot) - - create_screenshots_archive(screenshot_directory) + similarity_threshold = 0.99 + for test_screenshot, golden_image in zip(test_screenshots, golden_images): + screenshot_comparison_result = compare_screenshot_similarity( + test_screenshot, golden_image, similarity_threshold, True, screenshot_directory) + if screenshot_comparison_result != "Screenshots match": + raise ImageComparisonTestFailure(f"Screenshot test failed: {screenshot_comparison_result}") @pytest.mark.parametrize('rhi', ['dx12', 'vulkan']) @@ -219,7 +221,6 @@ class TestPerformanceBenchmarkSuite(object): @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_generic']) -@pytest.mark.system class TestMaterialEditor(object): @pytest.mark.parametrize("cfg_args,expected_lines", [ diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 11832f8846..5fa558ab1a 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -1,5 +1,6 @@ """ -Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. SPDX-License-Identifier: Apache-2.0 OR MIT @@ -8,12 +9,19 @@ import datetime import os import zipfile +from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots + + +class ImageComparisonTestFailure(Exception): + """Custom test failure for failed image comparisons.""" + pass + def create_screenshots_archive(screenshot_path): """ Creates a new zip file archive at archive_path containing all files listed within archive_path. :param screenshot_path: location containing the files to archive, the zip archive file will also be saved here. - :return: None, but creates a new zip file archive inside path containing all of the files inside archive_path. + :return: path to the created .zip file archive. """ files_to_archive = [] @@ -27,14 +35,16 @@ def create_screenshots_archive(screenshot_path): # Setup variables for naming the zip archive file. timestamp = datetime.datetime.now().timestamp() formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S") - screenshots_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip') + screenshots_zip_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip') # Write all of the valid .png and .ppm files to the archive file. - with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive: + with zipfile.ZipFile(screenshots_zip_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive: for file_path in files_to_archive: file_name = os.path.basename(file_path) zip_archive.write(file_path, file_name) + return screenshots_zip_file + def golden_images_directory(): """ @@ -53,6 +63,36 @@ def golden_images_directory(): return golden_images_dir +def compare_screenshot_similarity( + test_screenshot, golden_image, similarity_threshold, create_zip_archive=False, screenshot_directory=""): + """ + Compares the similarity between a test screenshot and a golden image. + It returns a "Screenshots match" string if the comparison mean value is higher than the similarity threshold. + Otherwise, it returns an error string. + :param test_screenshot: path to the test screenshot to compare. + :param golden_image: path to the golden image to compare. + :param similarity_threshold: value for the comparison mean value to be asserted against. + :param create_zip_archive: toggle to create a zip archive containing the screenshots if the assert check fails. + :param screenshot_directory: directory containing screenshots to create zip archive from. + :return: Error string if compared mean value < similarity threshold or screenshot_directory is missing for .zip, + otherwise it returns a "Screenshots match" string. + """ + error = "Screenshots match" + if create_zip_archive and not screenshot_directory: + error = 'You must specify a screenshot_directory in order to create a zip archive.\n' + + mean_similarity = compare_screenshots(test_screenshot, golden_image) + if not mean_similarity > similarity_threshold: + if create_zip_archive: + create_screenshots_archive(screenshot_directory) + error = ( + f"When comparing the test_screenshot: '{test_screenshot}' " + f"to golden_image: '{golden_image}' the mean similarity of '{mean_similarity}' " + f"was lower than the similarity threshold of '{similarity_threshold}'. ") + + return error + + def create_basic_atom_level(level_name): """ Creates a new level inside the Editor matching level_name & adds the following: diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py index 9515712583..4eb942b903 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py @@ -6,18 +6,6 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ import os -import sys - -import azlmbr.asset as asset -import azlmbr.bus as bus -import azlmbr.camera -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.math as math -import azlmbr.paths -import azlmbr.editor as editor - -sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.editor_test_helper import EditorTestHelper @@ -48,6 +36,15 @@ def run(): 12. Finally enters game mode, takes a screenshot, exits game mode, & saves the level. :return: None """ + import azlmbr.asset as asset + import azlmbr.bus as bus + import azlmbr.camera as camera + import azlmbr.entity as entity + import azlmbr.legacy.general as general + import azlmbr.math as math + import azlmbr.paths + import azlmbr.editor as editor + def initial_viewport_setup(screen_width, screen_height): general.set_viewport_size(screen_width, screen_height) general.update_viewport() @@ -147,22 +144,25 @@ def run(): parent_id=default_level.id ) azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0) - ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") - ground_plane_material_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) - ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset) - # Work around to add the correct Atom Mesh component + + # Work around to add the correct Atom Mesh component and asset. mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId ground_plane.components.append( editor.EditorComponentAPIBus( bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id] ).GetValue()[0] ) - ground_plane_mesh_asset_path = os.path.join("Objects", "plane.azmodel") + ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") ground_plane_mesh_asset = asset.AssetCatalogRequestBus( bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) hydra.get_set_test(ground_plane, 1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset) + # Add Atom Material component and asset. + ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") + ground_plane_material_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) + ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset) + # Create directional_light entity and set the properties directional_light = hydra.Entity("directional_light") directional_light.create_entity( @@ -180,11 +180,8 @@ def run(): components=["Material"], parent_id=default_level.id ) - sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") - sphere_material_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) - sphere.get_set_test(0, "Default Material|Material Asset", sphere_material_asset) - # Work around to add the correct Atom Mesh component + + # Work around to add the correct Atom Mesh component and asset. sphere.components.append( editor.EditorComponentAPIBus( bus.Broadcast, "AddComponentsOfType", sphere.id, [mesh_type_id] @@ -195,6 +192,12 @@ def run(): bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) hydra.get_set_test(sphere, 1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset) + # Add Atom Material component and asset. + sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") + sphere_material_asset = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) + sphere.get_set_test(0, "Default Material|Material Asset", sphere_material_asset) + # Create camera component and set the properties camera_entity = hydra.Entity("camera") position = math.Vector3(5.5, -12.0, 9.0) @@ -204,10 +207,9 @@ def run(): ) azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", camera_entity.id, rotation) camera_entity.get_set_test(0, "Controller|Configuration|Field of view", 60.0) - azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) + camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id) - # Save level, enter game mode, take screenshot, & exit game mode. - general.save_level() + # Enter game mode, take screenshot, & exit game mode. general.idle_wait(0.5) general.enter_game_mode() general.idle_wait(1.0) From 7fdb0c86fb5639e4ccb9196d810f62876f5f345a Mon Sep 17 00:00:00 2001 From: jromnoa Date: Tue, 26 Oct 2021 18:51:59 -0700 Subject: [PATCH 036/200] adds plane.fbx asset to TestData since test requires it Signed-off-by: jromnoa --- Gems/Atom/TestData/TestData/Objects/plane.fbx | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Gems/Atom/TestData/TestData/Objects/plane.fbx diff --git a/Gems/Atom/TestData/TestData/Objects/plane.fbx b/Gems/Atom/TestData/TestData/Objects/plane.fbx new file mode 100644 index 0000000000..b274bfa282 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Objects/plane.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a1f8d75dcd85e8b4aa57f6c0c81af0300ff96915ba3c2b591095c215d5e1d8c +size 12072 From f90074adb6e78addc635667c97b2c8bd7ca0a2a3 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 27 Oct 2021 15:54:03 -0700 Subject: [PATCH 037/200] [profiler_capture_api] added utility for reflecting AZ::Interfaces through the BehaviorContext Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/RTTI/BehaviorInterfaceProxy.h | 122 ++++++++++++++++++ .../AzCore/AzCore/azcore_files.cmake | 1 + 2 files changed, 123 insertions(+) create mode 100644 Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h new file mode 100644 index 0000000000..430524d3a2 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h @@ -0,0 +1,122 @@ +/* + * 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); + * }; + * + * void Reflect(AZ::ReflectContext* context) + * { + * if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + * { + * behaviorContext->ConstantProperty("g_MySystem", MySystemProxy::GetInstance) + * ->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}"); + + //! Accessor for use with ConstantProperty + 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; + } + + //! Helper for attaching interface function via ClassBuilder::Method + template + static auto WrapMethod() + { + using FuncTraits = AZStd::function_traits>; + return FuncTraits::template expand_args::template WrapMethod(); + } + + 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; } + + private: + template + struct MethodWrapper + { + template + static auto WrapMethod() + { + using return_type = AZStd::function_traits_get_result_t>; + return [](BehaviorInterfaceProxy* proxy, Args... params) -> return_type + { + if (proxy && proxy->IsValid()) + { + return AZStd::invoke(Method, proxy->m_instance, AZStd::forward(params)...); + } + return return_type(); + }; + } + }; + + AZStd::shared_ptr m_instance; + }; +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index d4a26256bf..3cd702e588 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -456,6 +456,7 @@ set(FILES RTTI/BehaviorContext.h RTTI/BehaviorContextUtilities.h RTTI/BehaviorContextUtilities.cpp + RTTI/BehaviorInterfaceProxy.h RTTI/BehaviorObjectSignals.h RTTI/TypeSafeIntegral.h Script/ScriptAsset.cpp From e7ed2c2a83f22c02886e2826ba9c733e87145f5a Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Wed, 27 Oct 2021 15:55:02 -0700 Subject: [PATCH 038/200] [profiler_capture_api] updated ProfilerRequests reflection to be as AZ::Interface Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/Debug/ProfilerReflection.cpp | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp index 72ad4b735b..430e320c54 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp @@ -9,11 +9,16 @@ #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 @@ -33,38 +38,46 @@ namespace AZ::Debug if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { behaviorContext->EBus("ProfilerNotificationBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Module, "debug") + ->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory) + ->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule) + ->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope) ->Handler(); } } }; - void ProfilerReflect(AZ::ReflectContext* context) + class ProfilerSystemScriptProxy + : public BehaviorInterfaceProxy { - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - if (AZ::EditContext* ec = serialize->GetEditContext()) - { - ProfilerNotificationBusHandler::Reflect(context); - } - } + public: + AZ_RTTI(ProfilerSystemScriptProxy, "{D671FB70-8B09-4C3A-96CD-06A339F3138E}", BehaviorInterfaceProxy); + }; + void ProfilerReflect(AZ::ReflectContext* context) + { if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->EBus("ProfilerRequestBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Module, "debug") + behaviorContext->ConstantProperty("g_ProfilerSystem", ProfilerSystemScriptProxy::GetInstance) + ->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) - ->Event("IsActive", &ProfilerRequestBus::Events::IsActive) - ->Event("SetActive", &ProfilerRequestBus::Events::SetActive) + ->Method("IsValid", &ProfilerSystemScriptProxy::IsValid) - ->Event("CaptureFrame", &ProfilerRequestBus::Events::CaptureFrame) + ->Method("IsActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::IsActive>()) + ->Method("SetActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::SetActive>()) - ->Event("StartCapture", &ProfilerRequestBus::Events::StartCapture) - ->Event("EndCapture", &ProfilerRequestBus::Events::EndCapture); + ->Method("CaptureFrame", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::CaptureFrame>()) - ProfilerNotificationBusHandler::Reflect(context); + ->Method("StartCapture", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::StartCapture>()) + ->Method("EndCapture", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::EndCapture>()); } + + ProfilerNotificationBusHandler::Reflect(context); } } // namespace AZ::Debug From 348bb7d37e5872cdfe36c310c4591551d512c357 Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Thu, 28 Oct 2021 13:49:08 +0100 Subject: [PATCH 039/200] Added setreg option for network spawnables serialization format Signed-off-by: Sergey Pereslavtsev --- .../Pipeline/NetworkPrefabProcessor.cpp | 32 +++++++++++++++---- .../Source/Pipeline/NetworkPrefabProcessor.h | 19 ++++++++++- Gems/Multiplayer/Registry/prefab.tools.setreg | 10 ++++-- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp index e9b7ace7c9..7e0e29030a 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp @@ -33,8 +33,10 @@ namespace Multiplayer mpTools->SetDidProcessNetworkPrefabs(false); } - context.ListPrefabs([&context](AZStd::string_view prefabName, PrefabDom& prefab) { - ProcessPrefab(context, prefabName, prefab); + AZ::DataStream::StreamType serializationFormat = GetAzSerializationFormat(); + + context.ListPrefabs([&context, serializationFormat](AZStd::string_view prefabName, PrefabDom& prefab) { + ProcessPrefab(context, prefabName, prefab, serializationFormat); }); if (mpTools && !context.GetProcessedObjects().empty()) @@ -47,7 +49,15 @@ namespace Multiplayer { if (auto* serializeContext = azrtti_cast(context); serializeContext != nullptr) { - serializeContext->Class()->Version(2); + serializeContext->Enum() + ->Value("Binary", SerializationFormats::Binary) + ->Value("Text", SerializationFormats::Text) + ; + + serializeContext->Class() + ->Version(3) + ->Field("SerializationFormat", &NetworkPrefabProcessor::m_serializationFormat) + ; } } @@ -130,7 +140,7 @@ namespace Multiplayer } } - void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab) + void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab, AZ::DataStream::StreamType serializationFormat) { using namespace AzToolsFramework::Prefab; @@ -144,10 +154,10 @@ namespace Multiplayer AZStd::string uniqueName = prefabName; uniqueName += ".network.spawnable"; - auto serializer = [](AZStd::vector& output, const ProcessedObjectStore& object) -> bool { + auto serializer = [serializationFormat](AZStd::vector& output, const ProcessedObjectStore& object) -> bool { AZ::IO::ByteContainerStream stream(&output); auto& asset = object.GetAsset(); - return AZ::Utils::SaveObjectToStream(stream, AZ::DataStream::ST_BINARY, &asset, asset.GetType()); + return AZ::Utils::SaveObjectToStream(stream, serializationFormat, &asset, asset.GetType()); }; auto&& [object, networkSpawnable] = @@ -218,4 +228,14 @@ namespace Multiplayer context.GetProcessedObjects().push_back(AZStd::move(object)); } + + AZ::DataStream::StreamType NetworkPrefabProcessor::GetAzSerializationFormat() const + { + if (m_serializationFormat == SerializationFormats::Text) + { + return AZ::DataStream::StreamType::ST_JSON; + } + + return AZ::DataStream::StreamType::ST_BINARY; + } } diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.h b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.h index 6eb0c2b4de..0fd3529db7 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.h +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.h @@ -9,6 +9,7 @@ #pragma once #include +#include namespace AzToolsFramework::Prefab::PrefabConversionUtils { @@ -33,7 +34,23 @@ namespace Multiplayer static void Reflect(AZ::ReflectContext* context); + //! The format the network spawnables are going to be stored in. + enum class SerializationFormats + { + Binary, //!< Binary is generally preferable for performance. + Text //!< Store in text format which is usually slower but helps with debugging. + }; + + AZ::DataStream::StreamType GetAzSerializationFormat() const; + protected: - static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab); + static void ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab, AZ::DataStream::StreamType serializationFormat); + + SerializationFormats m_serializationFormat = SerializationFormats::Binary; }; } + +namespace AZ +{ + AZ_TYPE_INFO_SPECIALIZE(Multiplayer::NetworkPrefabProcessor::SerializationFormats, "{F69B49EB-9D67-4D9C-99E7-DFA35D4ACCD2}"); +} diff --git a/Gems/Multiplayer/Registry/prefab.tools.setreg b/Gems/Multiplayer/Registry/prefab.tools.setreg index 7f25cf9a43..256f2d189a 100644 --- a/Gems/Multiplayer/Registry/prefab.tools.setreg +++ b/Gems/Multiplayer/Registry/prefab.tools.setreg @@ -18,8 +18,14 @@ "GameObjectCreation": [ { "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::EditorInfoRemover" }, - { "$type": "Multiplayer::NetworkPrefabProcessor" }, - { "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor" } + { + "$type": "Multiplayer::NetworkPrefabProcessor", + "SerializationFormat": "Binary" // Options are "Binary" (default) or "Text". Prefer "Binary" for performance. + }, + { + "$type": "AzToolsFramework::Prefab::PrefabConversionUtils::PrefabCatchmentProcessor", + "SerializationFormat": "Binary" // Options are "Binary" (default) or "Text". Prefer "Binary" for performance. + } ] } } From 8117798949f41f71531ea3bbe68fb13d11c012aa Mon Sep 17 00:00:00 2001 From: nggieber Date: Thu, 28 Oct 2021 07:00:21 -0700 Subject: [PATCH 040/200] Removed gem repo enable button Signed-off-by: nggieber --- .../Source/GemRepo/GemRepoItemDelegate.cpp | 67 +++---------------- .../Source/GemRepo/GemRepoItemDelegate.h | 11 +-- .../Source/GemRepo/GemRepoScreen.cpp | 15 ++--- 3 files changed, 16 insertions(+), 77 deletions(-) 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); From 43e6731714c6d93919d81d1a5088456a519a4ffc Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Thu, 28 Oct 2021 15:17:11 +0100 Subject: [PATCH 041/200] Removed hierarchy validation since it is not always applicable Signed-off-by: Sergey Pereslavtsev --- .../Pipeline/NetworkPrefabProcessor.cpp | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp index 7e0e29030a..19d997b8d1 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp @@ -105,41 +105,6 @@ namespace Multiplayer }); } - static bool HasNetHierarchyComponents(const AZ::Entity* entity) - { - return (entity->FindComponent() != nullptr) - || (entity->FindComponent() != nullptr); - } - - static void ValidateNetHierarchies(const AZStd::vector& prefabNetEntities) - { - AZStd::unordered_map prefabEntitesMap; - - for (auto* entity : prefabNetEntities) - { - auto* entityTransform = entity->FindComponent(); - AZ_Assert(entityTransform, "Net entities have to have Transform Component"); - - AZ::EntityId parentId = entityTransform->GetParentId(); - - // The input entities array is sorted in the parent to children order, - // so we only need to check against already iterated entities - if (parentId.IsValid() && prefabEntitesMap.contains(parentId)) - { - AZ::Entity* parentEntity = prefabEntitesMap[parentId]; - bool parentValid = HasNetHierarchyComponents(parentEntity); - AZ_Error("NetworkPrefabProcessor", parentValid, "Parent Entity %s must have a Network Hierarchy component assigned", - parentEntity->GetName().c_str()); - - bool childValid = HasNetHierarchyComponents(entity); - AZ_Error("NetworkPrefabProcessor", childValid, "Child Entity %s must have a Network Hierarchy component assigned", - entity->GetName().c_str()); - } - - prefabEntitesMap[entity->GetId()] = entity; - } - } - void NetworkPrefabProcessor::ProcessPrefab(PrefabProcessorContext& context, AZStd::string_view prefabName, PrefabDom& prefab, AZ::DataStream::StreamType serializationFormat) { using namespace AzToolsFramework::Prefab; @@ -178,9 +143,6 @@ namespace Multiplayer // Sort the entities prior to processing. The entities will end up in the net spawnable in this order. SpawnableUtils::SortEntitiesByTransformHierarchy(prefabNetEntities); - // Here we validate the hierarchical net entities have one of Network Hierarchy components. - ValidateNetHierarchies(prefabNetEntities); - // Create an asset for our future network spawnable: this allows us to put references to the asset in the components AZ::Data::Asset networkSpawnableAsset; networkSpawnableAsset.Create(networkSpawnable->GetId()); From 9109b9de8dc2a72c06db4746b95019e78e0e92ca Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Thu, 28 Oct 2021 15:19:11 +0100 Subject: [PATCH 042/200] Removed includes Signed-off-by: Sergey Pereslavtsev --- .../Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp index 19d997b8d1..bec659180c 100644 --- a/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp +++ b/Gems/Multiplayer/Code/Source/Pipeline/NetworkPrefabProcessor.cpp @@ -17,8 +17,6 @@ #include #include #include -#include -#include namespace Multiplayer { From c9a02e3c8ac1e090d730be8cf2af5bbec3be5414 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 25 Oct 2021 14:31:36 -0700 Subject: [PATCH 043/200] Revert "Lowering timeout so pytest doesnt abort, but still get mode time to read the server logs" This reverts commit 8380c5ff246c2c995e17b74a252cd0dd7f4e0bba. Signed-off-by: Gene Walters --- .../EditorPythonTestTools/editor_python_test_tools/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4d57f80bfb..713eb74f8c 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -90,7 +90,7 @@ class TestHelper: found_unexpected_lines = [x for x in found_lines if unexpected_line in x] Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) - TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 90.0) + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30*60.0) # @todo delete! debugging Jenkins Report.info("PRINTING THE ENTIRE SERVER LOG!") From 48c438f469214f22119e51bf29d9d5ff1851b07a Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 25 Oct 2021 14:46:03 -0700 Subject: [PATCH 044/200] Reverting the debugging code I was using to narrow down the problem on Jenkins now that the issue was fixed by PR-4946 Signed-off-by: Gene Walters --- .../editor_python_test_tools/utils.py | 21 ++--------------- .../TcpTransport/TcpNetworkInterface.cpp | 5 ---- .../AzNetworking/TcpTransport/TcpSocket.cpp | 23 +++---------------- .../LevelSystem/SpawnableLevelSystem.cpp | 2 +- .../remote_console_commands.py | 2 +- 5 files changed, 7 insertions(+), 46 deletions(-) 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 713eb74f8c..d6f33a1726 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -83,31 +83,14 @@ class TestHelper: with Tracer() as section_tracer: multiplayer.PythonEditorFuncs_enter_game_mode() general.idle_wait_frames(1) - + # Make sure the server launcher binary exists unexpected_line = "LaunchEditorServer failed! The ServerLauncher binary is missing!" found_lines = [printInfo.message.strip() for printInfo in section_tracer.errors] found_unexpected_lines = [x for x in found_lines if unexpected_line in x] Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) - TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30*60.0) - - # @todo delete! debugging Jenkins - Report.info("PRINTING THE ENTIRE SERVER LOG!") - - serverlog_filename = os.path.join(os.getcwd(), 'AutomatedTesting/user/log/Server.log') - - with open(serverlog_filename) as server_log_file: - Report.info( server_log_file.read() ) - Report.info("END: PRINTING THE ENTIRE SERVER LOG") - - #if not multiplayer.PythonEditorFuncs_is_in_game_mode(): - # 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 - # for line in expected_lines_server: - # assert server_console.expect_log_line(line, EXPECTEDLINE_WAIT_TIME_SECONDS), f"Expected line not found: {line}" - - + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30.0) Report.critical_result(msgtuple_success_fail, multiplayer.PythonEditorFuncs_is_in_game_mode()) @staticmethod diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp index c2d9f5f1d2..1ccff7be50 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpNetworkInterface.cpp @@ -79,8 +79,6 @@ namespace AzNetworking ConnectionId TcpNetworkInterface::Connect(const IpAddress& remoteAddress) { - AZLOG_INFO("Attemping TcpNetworkInterface::Connect") - const ConnectionId connectionId = m_connectionSet.GetNextConnectionId(); AZStd::unique_ptr connection = AZStd::make_unique(connectionId, remoteAddress, *this, m_trustZone, net_TcpUseEncryption); AZ_Assert(connection->GetConnectionRole() == ConnectionRole::Connector, "Invalid role for connection"); @@ -89,9 +87,6 @@ namespace AzNetworking TcpSocket* tcpSocket = connection->GetTcpSocket(); if (tcpSocket == nullptr) { - AZLOG_ERROR( - "TcpNetworkInterface::Connect tcpSocket is null! How can this be? Returning InvalidConnectionId") - return InvalidConnectionId; } diff --git a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp index f3b62e1913..e469b70640 100644 --- a/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp +++ b/Code/Framework/AzNetworking/AzNetworking/TcpTransport/TcpSocket.cpp @@ -68,30 +68,13 @@ namespace AzNetworking { Close(); - if (!SocketCreateInternal()) - { - AZ_Warning("TcpSocket", false, "Tcp::Connect failed. SocketCreateInternal is false"); - - Close(); - return false; - } - - if (!BindSocketForConnectInternal(address)) - { - AZ_Warning("TcpSocket", false, "Tcp::Connect failed. BindSocketForConnectInternal is false"); - - Close(); - return false; - } - - if (!(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd))) + if (!SocketCreateInternal() + || !BindSocketForConnectInternal(address) + || !(SetSocketNonBlocking(m_socketFd) && SetSocketNoDelay(m_socketFd))) { - AZ_Warning("TcpSocket", false, "Tcp::Connect failed. SetSocketNonBlocking and SetSocketNoDelay is false"); - Close(); return false; } - return true; } diff --git a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index ad15abd2b7..b2b67c3b75 100644 --- a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -152,7 +152,7 @@ namespace LegacyLevelSystem // [LYN-2376] Remove once legacy slice support is removed int SpawnableLevelSystem::GetLevelCount() { - AZ_Warning("SpawnableLevelSystem", false, "GetLevelCount - No longer supported."); + AZ_Assert(false, "GetLevelCount - No longer supported."); return 0; } diff --git a/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py b/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py index 31ec6663fb..559823c820 100755 --- a/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py +++ b/Tools/RemoteConsole/ly_remote_console/ly_remote_console/remote_console_commands.py @@ -228,7 +228,7 @@ class RemoteConsole: def expect_log_line(self, match_string, timeout=30): # type: (str, int) -> bool """ - Looks for a log line event to expect within a time frame. Returns False if timeout is reached. + Looks for a log line event to expect within a time frame. Returns False is timeout is reached. :param match_string: The string to match that acts as a key :param timeout: The timeout to wait for the log line in seconds :return: boolean True if match_string found, False otherwise. From 4996e76f6ca43f390e361cf44eb2f5d9f90ba779 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Fri, 22 Oct 2021 18:00:43 -0700 Subject: [PATCH 045/200] Read engine version from setting registry (#4926) * Read engine version from setting registry Signed-off-by: Junbo Liang Signed-off-by: Gene Walters --- .../Code/Include/Private/IdentityProvider.h | 2 + .../Code/Source/IdentityProvider.cpp | 46 +++++++------------ .../AWSMetrics/Code/Tests/AWSMetricsGemMock.h | 6 +-- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/Gems/AWSMetrics/Code/Include/Private/IdentityProvider.h b/Gems/AWSMetrics/Code/Include/Private/IdentityProvider.h index 1309e2749c..f70b2c7e10 100644 --- a/Gems/AWSMetrics/Code/Include/Private/IdentityProvider.h +++ b/Gems/AWSMetrics/Code/Include/Private/IdentityProvider.h @@ -14,6 +14,8 @@ namespace AWSMetrics { + constexpr const char* EngineVersionJsonKey = "O3DEVersion"; + //! Base class to be implemented by IdentityProvider to retrive an ID for identity. class IdentityProvider { diff --git a/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp b/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp index bc8ff9a42e..d0ab8a1a8c 100644 --- a/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp +++ b/Gems/AWSMetrics/Code/Source/IdentityProvider.cpp @@ -8,10 +8,10 @@ #include -#include #include -#include -#include +#include +#include +#include namespace AWSMetrics { @@ -22,37 +22,23 @@ namespace AWSMetrics AZStd::string IdentityProvider::GetEngineVersion() { - static constexpr const char* EngineConfigFilePath = "@products@/engine.json"; - static constexpr const char* EngineVersionJsonKey = "O3DEVersion"; - - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetDirectInstance(); - if (!fileIO) - { - AZ_Error("AWSMetrics", false, "No FileIoBase Instance"); - return ""; - } - - char resolvedPath[AZ_MAX_PATH_LEN] = { 0 }; - if (!fileIO->ResolvePath(EngineConfigFilePath, resolvedPath, AZ_MAX_PATH_LEN)) + constexpr auto engineVersionKey = AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::EngineSettingsRootKey) + "/" + EngineVersionJsonKey; + AZStd::string engineVersion; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr && settingsRegistry->Get(engineVersion, engineVersionKey)) { - AZ_Error("AWSMetrics", false, "Failed to resolve the engine config file directory"); - return ""; + return engineVersion; } - auto readOutcome = AZ::JsonSerializationUtils::ReadJsonFile(resolvedPath); - if (!readOutcome.IsSuccess()) + auto engineSettingsPath = AZ::IO::FixedMaxPath{ AZ::Utils::GetEnginePath() } / "engine.json"; + if (AZ::IO::SystemFile::Exists(engineSettingsPath.c_str())) { - AZ_Error("AWSMetrics", false, readOutcome.GetError().c_str()); - return ""; + AZ::SettingsRegistryImpl settingsRegistry; + if (settingsRegistry.MergeSettingsFile( + engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::EngineSettingsRootKey)) + { + settingsRegistry.Get(engineVersion, engineVersionKey); + } } - - rapidjson_ly::Document& jsonDoc = readOutcome.GetValue(); - auto memberIt = jsonDoc.FindMember(EngineVersionJsonKey); - if (memberIt != jsonDoc.MemberEnd()) - { - return memberIt->value.GetString(); - } - - return ""; + return engineVersion; } } diff --git a/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h b/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h index 4f40fd6ff1..f8fb9e174c 100644 --- a/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h +++ b/Gems/AWSMetrics/Code/Tests/AWSMetricsGemMock.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -47,9 +48,6 @@ namespace AWSMetrics m_localFileIO->SetAlias("@engroot@", engineRoot.c_str()); m_localFileIO->SetAlias("@products@", productAssetPath.c_str()); m_localFileIO->SetAlias("@user@", userPath.c_str()); - // Copy engine.json to the cache - EXPECT_TRUE(m_localFileIO->Copy((engineRoot / "engine.json").c_str(), "engine.json")); - m_serializeContext = AZStd::make_unique(); m_registrationContext = AZStd::make_unique(); @@ -61,6 +59,8 @@ namespace AWSMetrics m_settingsRegistry->SetContext(m_serializeContext.get()); m_settingsRegistry->SetContext(m_registrationContext.get()); + m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder, engineRoot.c_str()); + AZ::SettingsRegistry::Register(m_settingsRegistry.get()); } From cea5a0d187452e04c617d48bf6c06d871436bc9c Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Fri, 22 Oct 2021 16:12:18 -0700 Subject: [PATCH 046/200] Fix desktop shortcuts created by Windows installer Signed-off-by: AMZN-Phil Signed-off-by: Gene Walters --- cmake/Platform/Windows/Packaging/Shortcuts.wxs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/Platform/Windows/Packaging/Shortcuts.wxs b/cmake/Platform/Windows/Packaging/Shortcuts.wxs index fbfa174d06..1299626bf4 100644 --- a/cmake/Platform/Windows/Packaging/Shortcuts.wxs +++ b/cmake/Platform/Windows/Packaging/Shortcuts.wxs @@ -29,13 +29,13 @@ From 6da17abba48006071e21ad747f5bdf27a4c57b53 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 21 Oct 2021 23:18:08 -0700 Subject: [PATCH 047/200] Made material property auto-rename procedure apply to Material Component at runtime. This ensures that an material property overrides and any gameplay scripts that work with property overrides can get the benefit of the material type version update procedure. I added an ApplyPropertyRenames function to MaterialTypeAsset very similar to the one in MaterialTypeSourceData. Updated the MaterialAssignment class to apply any property renames when it discovers the old name doesn't work. This will be written to disk when the level or prefab is saved. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> Signed-off-by: Gene Walters --- .../Materials/MinimalBlue.material | 17 ++++ .../Source/Material/MaterialAssignment.cpp | 33 +++++++- .../RPI.Reflect/Material/MaterialTypeAsset.h | 4 + .../Material/MaterialVersionUpdate.h | 4 + .../Material/MaterialTypeAsset.cpp | 16 ++++ .../Material/MaterialVersionUpdate.cpp | 16 ++++ .../Tests/Material/MaterialTypeAssetTests.cpp | 83 +++++++++++++++++++ 7 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 AutomatedTesting/Materials/MinimalBlue.material diff --git a/AutomatedTesting/Materials/MinimalBlue.material b/AutomatedTesting/Materials/MinimalBlue.material new file mode 100644 index 0000000000..7310a90250 --- /dev/null +++ b/AutomatedTesting/Materials/MinimalBlue.material @@ -0,0 +1,17 @@ +{ + "description": "", + "parentMaterial": "", + "materialType": "TestData/Materials/Types/MinimalPBR.materialtype", + "materialTypeVersion": 3, + "properties": { + "settings": { + "color": [ + 0.08522164076566696, + 0.11898985505104065, + 1.0, + 1.0 + ], + "roughness": 0.33000001311302185 + } + } +} \ No newline at end of file diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index 8984ec160b..f8a8d17c55 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -137,11 +137,33 @@ namespace AZ if (m_materialInstance->CanCompile()) { + AZStd::vector> renamedProperties; + for (const auto& propertyPair : m_propertyOverrides) { if (!propertyPair.second.empty()) { - const auto& materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first); + RPI::MaterialPropertyIndex materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first); + + // If we didn't find the name, check to see if there was a rename that should be used. + if (materialPropertyIndex.IsNull()) + { + Name propertyId = propertyPair.first; + + if (m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(propertyId)) + { + renamedProperties.emplace_back(propertyPair.first, propertyId); + + // We should be able to find the property now, using the new name + materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyId); + + AZ_Warning("MaterialAssignment", false, + "Material property '%s' has been renamed to '%s', and a material override references the old name. Save the level or prefab to permanently apply this change.", + propertyPair.first.GetCStr(), + propertyId.GetCStr()); + } + } + if (!materialPropertyIndex.IsNull()) { m_materialInstance->SetPropertyValue( @@ -150,6 +172,15 @@ namespace AZ } } + // Now that we're done looping over all the overrides, it's safe to apply any renames that were scheduled + for (auto& pair : renamedProperties) + { + const Name& oldName = pair.first; + const Name& newName = pair.second; + m_propertyOverrides[newName] = m_propertyOverrides[oldName]; + m_propertyOverrides.erase(oldName); + } + return m_materialInstance->Compile(); } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialTypeAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialTypeAsset.h index 9bc0e018d3..f194d84263 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialTypeAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialTypeAsset.h @@ -129,6 +129,10 @@ namespace AZ const AZStd::vector& GetMaterialVersionUpdateList() const { return m_materialVersionUpdates; } + //! Possibly renames @propertyId based on the material version update steps. + //! @return true if the property was renamed + bool ApplyPropertyRenames(AZ::Name& propertyId) const; + private: bool PostLoadInit() override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialVersionUpdate.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialVersionUpdate.h index eb71ad9cb7..3ecfe7b5e0 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialVersionUpdate.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialVersionUpdate.h @@ -44,6 +44,10 @@ namespace AZ uint32_t GetVersion() const; void SetVersion(uint32_t toVersion); + + //! Possibly renames @propertyId based on the material version update steps. + //! @return true if the property was renamed + bool ApplyPropertyRenames(AZ::Name& propertyId) const; //! Apply version updates to the given material asset. //! @return true if any changes were made diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp index 522ba74119..76634201eb 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialTypeAsset.cpp @@ -169,6 +169,22 @@ namespace AZ return m_version; } + + bool MaterialTypeAsset::ApplyPropertyRenames(AZ::Name& propertyId) const + { + bool renamed = false; + + for (const auto& versionUpdates : m_materialVersionUpdates) + { + if (versionUpdates.ApplyPropertyRenames(propertyId)) + { + renamed = true; + } + } + + return renamed; + } + void MaterialTypeAsset::SetReady() { m_status = AssetStatus::Ready; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialVersionUpdate.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialVersionUpdate.cpp index b387e502e2..f5dfe9e80c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialVersionUpdate.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialVersionUpdate.cpp @@ -56,6 +56,22 @@ namespace AZ { m_toVersion = toVersion; } + + bool MaterialVersionUpdate::ApplyPropertyRenames(AZ::Name& propertyId) const + { + bool renamed = false; + + for (const auto& action : m_actions) + { + if (action.m_fromPropertyId == propertyId) + { + propertyId = action.m_toPropertyId; + renamed = true; + } + } + + return renamed; + } bool MaterialVersionUpdate::ApplyVersionUpdates(MaterialAsset& materialAsset) const { diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeAssetTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeAssetTests.cpp index 81b723ec04..382ab4e149 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeAssetTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTypeAssetTests.cpp @@ -1041,5 +1041,88 @@ namespace UnitTest EXPECT_FALSE(materialTypeAsset->GetShaderCollection()[1].MaterialOwnsShaderOption(Name{"o_globalOption_inShaderB"})); } + TEST_F(MaterialTypeAssetTests, ApplyPropertyRenames) + { + Data::Asset materialTypeAsset; + + auto addRenameAction = [](MaterialVersionUpdate& versionUpdate, const char* from, const char* to) + { + versionUpdate.AddAction(MaterialVersionUpdate::RenamePropertyAction( + { + Name{ from }, + Name{ to } + })); + }; + + MaterialTypeAssetCreator materialTypeCreator; + materialTypeCreator.Begin(Uuid::CreateRandom()); + + // Version updates + materialTypeCreator.SetVersion(10); + + MaterialVersionUpdate versionUpdate2(2); + addRenameAction(versionUpdate2, "general.fooA", "general.fooB"); + materialTypeCreator.AddVersionUpdate(versionUpdate2); + + MaterialVersionUpdate versionUpdate4(4); + addRenameAction(versionUpdate4, "general.barA", "general.barB"); + materialTypeCreator.AddVersionUpdate(versionUpdate4); + + MaterialVersionUpdate versionUpdate6(6); + addRenameAction(versionUpdate6, "general.fooB", "general.fooC"); + addRenameAction(versionUpdate6, "general.barB", "general.barC"); + materialTypeCreator.AddVersionUpdate(versionUpdate6); + + MaterialVersionUpdate versionUpdate7(7); + addRenameAction(versionUpdate7, "general.bazA", "otherGroup.bazB"); + materialTypeCreator.AddVersionUpdate(versionUpdate7); + + materialTypeCreator.BeginMaterialProperty(Name{ "general.fooC" }, MaterialPropertyDataType::Bool); + materialTypeCreator.EndMaterialProperty(); + materialTypeCreator.BeginMaterialProperty(Name{ "general.barC" }, MaterialPropertyDataType::Bool); + materialTypeCreator.EndMaterialProperty(); + materialTypeCreator.BeginMaterialProperty(Name{ "otherGroup.bazB" }, MaterialPropertyDataType::Bool); + materialTypeCreator.EndMaterialProperty(); + + EXPECT_TRUE(materialTypeCreator.End(materialTypeAsset)); + + AZ::Name propertyId; + + propertyId = AZ::Name{"doesNotExist"}; + EXPECT_FALSE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "doesNotExist"); + + propertyId = AZ::Name{"general.fooA"}; + EXPECT_TRUE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "general.fooC"); + + propertyId = AZ::Name{"general.fooB"}; + EXPECT_TRUE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "general.fooC"); + + propertyId = AZ::Name{"general.fooC"}; + EXPECT_FALSE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "general.fooC"); + + propertyId = AZ::Name{"general.barA"}; + EXPECT_TRUE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "general.barC"); + + propertyId = AZ::Name{"general.barB"}; + EXPECT_TRUE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "general.barC"); + + propertyId = AZ::Name{"general.barC"}; + EXPECT_FALSE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "general.barC"); + + propertyId = AZ::Name{"general.bazA"}; + EXPECT_TRUE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "otherGroup.bazB"); + + propertyId = AZ::Name{"otherGroup.bazB"}; + EXPECT_FALSE(materialTypeAsset->ApplyPropertyRenames(propertyId)); + EXPECT_STREQ(propertyId.GetCStr(), "otherGroup.bazB"); + } } From 334899b0dcdd715f9b8b1ad7d56f9fbc019c295a Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 22 Oct 2021 16:41:44 -0700 Subject: [PATCH 048/200] Moved the Material Component property override renaming to EditorMaterialComponent via ApplyAutomaticPropertyUpdates. MaterialAssignment::ApplyProperties() still reports warnings but does not update the m_propertyOverrides. MaterialAssignment::ApplyProperties() will now skip the old name'd overrides if overrides are present for the new names. I'm not sure if this will ever happen, but it did happen while I had some intermediate changes, so I imagine it could happen again. I had to update the Material::FindPropertyIndex function to expose information about renames when they occur. This should make it easier for other systems to get (somewhat) automatic benefit from the version update feature. I also found that there was an issue with material inspector where it wouldn't be initialized the the right override values when renames were present. Now it applies the renames to whatever override data it gets from the Material Component. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> Signed-off-by: Gene Walters --- .../Source/Material/MaterialAssignment.cpp | 44 +++++++------------ .../Atom/RPI.Public/Material/Material.h | 4 +- .../Source/RPI.Public/Material/Material.cpp | 34 +++++++++++++- .../RPI/Code/Tests/Material/MaterialTests.cpp | 31 +++++++++++++ .../Material/MaterialComponentBus.h | 3 ++ .../Material/EditorMaterialComponent.cpp | 13 ++++++ .../EditorMaterialComponentInspector.cpp | 21 +++++++++ .../Material/MaterialComponentController.cpp | 34 ++++++++++++++ .../Material/MaterialComponentController.h | 1 + 9 files changed, 154 insertions(+), 31 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp index f8a8d17c55..c79ceb39ba 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignment.cpp @@ -137,31 +137,28 @@ namespace AZ if (m_materialInstance->CanCompile()) { - AZStd::vector> renamedProperties; - for (const auto& propertyPair : m_propertyOverrides) { if (!propertyPair.second.empty()) { - RPI::MaterialPropertyIndex materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first); + bool wasRenamed = false; + Name newName; + RPI::MaterialPropertyIndex materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyPair.first, &wasRenamed, &newName); + + // FindPropertyIndex will have already reported a message about what the old and new names are. Here we just add some extra info to help the user resolve it. + AZ_Warning("MaterialAssignment", !wasRenamed, + "Consider running \"Apply Automatic Property Updates\" to use the latest property names.", + propertyPair.first.GetCStr(), + newName.GetCStr()); - // If we didn't find the name, check to see if there was a rename that should be used. - if (materialPropertyIndex.IsNull()) + if (wasRenamed && m_propertyOverrides.find(newName) != m_propertyOverrides.end()) { - Name propertyId = propertyPair.first; - - if (m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(propertyId)) - { - renamedProperties.emplace_back(propertyPair.first, propertyId); - - // We should be able to find the property now, using the new name - materialPropertyIndex = m_materialInstance->FindPropertyIndex(propertyId); - - AZ_Warning("MaterialAssignment", false, - "Material property '%s' has been renamed to '%s', and a material override references the old name. Save the level or prefab to permanently apply this change.", - propertyPair.first.GetCStr(), - propertyId.GetCStr()); - } + materialPropertyIndex.Reset(); + + AZ_Warning("MaterialAssignment", false, + "Material property '%s' has been renamed to '%s', and a property override exists for both. The one with the old name will be ignored.", + propertyPair.first.GetCStr(), + newName.GetCStr()); } if (!materialPropertyIndex.IsNull()) @@ -172,15 +169,6 @@ namespace AZ } } - // Now that we're done looping over all the overrides, it's safe to apply any renames that were scheduled - for (auto& pair : renamedProperties) - { - const Name& oldName = pair.first; - const Name& newName = pair.second; - m_propertyOverrides[newName] = m_propertyOverrides[oldName]; - m_propertyOverrides.erase(oldName); - } - return m_materialInstance->Compile(); } diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h index d8a0cf0e7d..72c8616a73 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Material/Material.h @@ -71,7 +71,9 @@ namespace AZ virtual ~Material(); //! Finds the material property index from the material property ID - MaterialPropertyIndex FindPropertyIndex(const Name& propertyId) const; + //! @param wasRenamed optional parameter that is set to true if @propertyId is an old name and an automatic rename was applied to find the index. + //! @param newName optional parameter that is set to the new property name, if the property was renamed. + MaterialPropertyIndex FindPropertyIndex(const Name& propertyId, bool* wasRenamed = nullptr, Name* newName = nullptr) const; //! Sets the value of a material property. The template data type must match the property's data type. //! @return true if property value was changed diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp index c87646e17d..050ae47749 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Material/Material.cpp @@ -386,9 +386,39 @@ namespace AZ return m_currentChangeId; } - MaterialPropertyIndex Material::FindPropertyIndex(const Name& propertyId) const + MaterialPropertyIndex Material::FindPropertyIndex(const Name& propertyId, bool* wasRenamed, Name* newName) const { - return m_layout->FindPropertyIndex(propertyId); + if (wasRenamed) + { + *wasRenamed = false; + } + + MaterialPropertyIndex index = m_layout->FindPropertyIndex(propertyId); + if (!index.IsValid()) + { + Name renamedId = propertyId; + + if (m_materialAsset->GetMaterialTypeAsset()->ApplyPropertyRenames(renamedId)) + { + index = m_layout->FindPropertyIndex(renamedId); + + if (wasRenamed) + { + *wasRenamed = true; + } + + if (newName) + { + *newName = renamedId; + } + + AZ_Warning("Material", false, + "Material property '%s' has been renamed to '%s'. Consider updating the corresponding source data.", + propertyId.GetCStr(), + renamedId.GetCStr()); + } + } + return index; } template diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp index f202747bf6..9c3e08ee08 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialTests.cpp @@ -857,4 +857,35 @@ namespace UnitTest EXPECT_EQ(material->GetPropertyValue(material->FindPropertyIndex(Name{ "MyInt" })), -7); EXPECT_EQ(srgData->GetConstant(srgData->FindShaderInputConstantIndex(Name{ "m_int" })), -7); } + + TEST_F(MaterialTests, TestFindPropertyIndexUsingOldName) + { + MaterialTypeAssetCreator materialTypeCreator; + materialTypeCreator.Begin(Uuid::CreateRandom()); + materialTypeCreator.AddShader(m_testMaterialShaderAsset); + AddCommonTestMaterialProperties(materialTypeCreator); + materialTypeCreator.SetVersion(2); + MaterialVersionUpdate versionUpdate(2); + versionUpdate.AddAction(MaterialVersionUpdate::RenamePropertyAction({Name{ "OldName" },Name{ "MyInt" }})); + materialTypeCreator.AddVersionUpdate(versionUpdate); + materialTypeCreator.End(m_testMaterialTypeAsset); + + MaterialAssetCreator materialCreator; + materialCreator.Begin(Uuid::CreateRandom(), *m_testMaterialTypeAsset); + materialCreator.End(m_testMaterialAsset); + + Data::Instance material = Material::FindOrCreate(m_testMaterialAsset); + + bool wasRenamed = false; + Name newName; + MaterialPropertyIndex indexFromOldName = material->FindPropertyIndex(Name{"OldName"}, &wasRenamed, &newName); + EXPECT_TRUE(wasRenamed); + EXPECT_EQ(newName, Name{"MyInt"}); + + MaterialPropertyIndex indexFromNewName = material->FindPropertyIndex(Name{"MyInt"}, &wasRenamed, &newName); + EXPECT_FALSE(wasRenamed); + + EXPECT_EQ(indexFromOldName, indexFromNewName); + } + } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h index ed7f1564ac..293080367d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h @@ -43,6 +43,9 @@ namespace AZ virtual void ClearInvalidMaterialOverrides() = 0; //! Repair materials that reference missing assets by assigning the default asset virtual void RepairInvalidMaterialOverrides() = 0; + //! Repair material property overrides that reference missing properties by auto-renaming them where possible + //! @return the number of properties that were updated + virtual uint32_t ApplyAutomaticPropertyUpdates() = 0; //! Set default material override virtual void SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) = 0; //! Get default material override diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index a3ae61b14b..94beeb2430 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -240,6 +240,19 @@ namespace AZ UpdateMaterialSlots(); }); action->setToolTip("Repair materials that reference missing assets by assigning the default asset."); + + action = menu->addAction("Apply Automatic Property Updates", [this]() { + AzToolsFramework::ScopedUndoBatch undoBatch("Applying automatic property updates."); + SetDirty(); + + uint32_t propertiesUpdated = 0; + MaterialComponentRequestBus::EventResult(propertiesUpdated, GetEntityId(), &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates); + + AZ_Printf("EditorMaterialComponent", "Updated %u property(s).", propertiesUpdated); + + UpdateMaterialSlots(); + }); + action->setToolTip("Repair material property overrides that reference missing properties by auto-renaming them where possible."); } void EditorMaterialComponent::SetPrimaryAsset(const AZ::Data::AssetId& assetId) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index b6875e2e9c..4ef96a13dd 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -352,6 +352,27 @@ namespace AZ m_editData.m_materialPropertyOverrideMap, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides, m_materialAssignmentId); + // Apply any automatic property renames so that the material inspector will be property initialized with the right values + // for properties that have new names. + { + AZStd::vector> renamedProperties; + for (auto& propertyOverridePair : m_editData.m_materialPropertyOverrideMap) + { + Name name = propertyOverridePair.first; + if (m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(name)) + { + renamedProperties.emplace_back(propertyOverridePair.first, name); + } + } + for (auto& renamePair : renamedProperties) + { + const Name& oldName = renamePair.first; + const Name& newName = renamePair.second; + m_editData.m_materialPropertyOverrideMap[newName] = m_editData.m_materialPropertyOverrideMap[oldName]; + m_editData.m_materialPropertyOverrideMap.erase(oldName); + } + } + for (auto& group : m_groups) { for (auto& property : group.second.m_properties) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 4c26042a26..335434758b 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -49,6 +49,7 @@ namespace AZ ->Event("ClearIncompatibleMaterialOverrides", &MaterialComponentRequestBus::Events::ClearIncompatibleMaterialOverrides) ->Event("ClearInvalidMaterialOverrides", &MaterialComponentRequestBus::Events::ClearInvalidMaterialOverrides) ->Event("RepairInvalidMaterialOverrides", &MaterialComponentRequestBus::Events::RepairInvalidMaterialOverrides) + ->Event("ApplyAutomaticPropertyUpdates", &MaterialComponentRequestBus::Events::ApplyAutomaticPropertyUpdates) ->Event("SetMaterialOverride", &MaterialComponentRequestBus::Events::SetMaterialOverride) ->Event("GetMaterialOverride", &MaterialComponentRequestBus::Events::GetMaterialOverride) ->Event("ClearMaterialOverride", &MaterialComponentRequestBus::Events::ClearMaterialOverride) @@ -406,6 +407,39 @@ namespace AZ } LoadMaterials(); } + + uint32_t MaterialComponentController::ApplyAutomaticPropertyUpdates() + { + uint32_t propertiesUpdated = 0; + + for (auto& materialAssignmentPair : m_configuration.m_materials) + { + MaterialAssignment& materialAssignment = materialAssignmentPair.second; + + AZStd::vector> renamedProperties; + + for (const auto& propertyPair : materialAssignment.m_propertyOverrides) + { + Name propertyId = propertyPair.first; + + if (materialAssignment.m_materialInstance->GetAsset()->GetMaterialTypeAsset()->ApplyPropertyRenames(propertyId)) + { + renamedProperties.emplace_back(propertyPair.first, propertyId); + ++propertiesUpdated; + } + } + + for (auto& pair : renamedProperties) + { + const Name& oldName = pair.first; + const Name& newName = pair.second; + materialAssignment.m_propertyOverrides[newName] = materialAssignment.m_propertyOverrides[oldName]; + materialAssignment.m_propertyOverrides.erase(oldName); + } + } + + return propertiesUpdated; + } void MaterialComponentController::SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index 1594456a31..ec542c377c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -58,6 +58,7 @@ namespace AZ void ClearIncompatibleMaterialOverrides() override; void ClearInvalidMaterialOverrides() override; void RepairInvalidMaterialOverrides() override; + uint32_t ApplyAutomaticPropertyUpdates() override; void SetDefaultMaterialOverride(const AZ::Data::AssetId& materialAssetId) override; const AZ::Data::AssetId GetDefaultMaterialOverride() const override; void ClearDefaultMaterialOverride() override; From 725ac836672e7991b561243179b44413100749d0 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Sat, 23 Oct 2021 00:02:31 -0700 Subject: [PATCH 049/200] Minor updates in response to code review feedback. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> Signed-off-by: Gene Walters --- .../Source/Material/EditorMaterialComponentInspector.cpp | 6 ++---- .../Code/Source/Material/MaterialComponentController.cpp | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index 4ef96a13dd..9af3b41b12 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -352,7 +352,7 @@ namespace AZ m_editData.m_materialPropertyOverrideMap, m_entityId, &MaterialComponentRequestBus::Events::GetPropertyOverrides, m_materialAssignmentId); - // Apply any automatic property renames so that the material inspector will be property initialized with the right values + // Apply any automatic property renames so that the material inspector will be properly initialized with the right values // for properties that have new names. { AZStd::vector> renamedProperties; @@ -364,10 +364,8 @@ namespace AZ renamedProperties.emplace_back(propertyOverridePair.first, name); } } - for (auto& renamePair : renamedProperties) + for (const auto& [oldName, newName] : renamedProperties) { - const Name& oldName = renamePair.first; - const Name& newName = renamePair.second; m_editData.m_materialPropertyOverrideMap[newName] = m_editData.m_materialPropertyOverrideMap[oldName]; m_editData.m_materialPropertyOverrideMap.erase(oldName); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 335434758b..07082a87d5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -428,11 +428,9 @@ namespace AZ ++propertiesUpdated; } } - - for (auto& pair : renamedProperties) + + for (const auto& [oldName, newName] : renamedProperties) { - const Name& oldName = pair.first; - const Name& newName = pair.second; materialAssignment.m_propertyOverrides[newName] = materialAssignment.m_propertyOverrides[oldName]; materialAssignment.m_propertyOverrides.erase(oldName); } From 4ce40281dfb5292105ba508a5f20573150d7b2c9 Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:35:50 +0200 Subject: [PATCH 050/200] Asset Browser Search View fixes (#4814) * Fixed RowCount method. Signed-off-by: igarri * Fixed Signals Signed-off-by: igarri * Fixed Delegate case Signed-off-by: igarri * Fixed issue when displaying branch icons Signed-off-by: igarri * Fixed AssetBrowser Delegate Signed-off-by: igarri * Removed optimize flags Signed-off-by: igarri * AssetBrowsertableModel cleanup Signed-off-by: igarri * Fixed Typos Signed-off-by: igarri * Fixed Comment Signed-off-by: igarri * Added check for rowCount == 0 Signed-off-by: igarri Signed-off-by: Gene Walters --- .../AzAssetBrowser/AzAssetBrowserWindow.cpp | 54 +------------------ .../AzAssetBrowser/AzAssetBrowserWindow.h | 1 - .../AssetBrowser/AssetBrowserTableModel.cpp | 42 ++++++--------- .../AssetBrowser/AssetBrowserTableModel.h | 6 ++- .../AssetBrowser/Views/EntryDelegate.cpp | 37 +++++++------ 5 files changed, 43 insertions(+), 97 deletions(-) diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp index 9fe4cfd0d2..bcaaa02b67 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp @@ -96,10 +96,6 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent) connect( m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this, &AzAssetBrowserWindow::SetTableViewVisibleAfterFilter); - - connect( - m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this, - &AzAssetBrowserWindow::UpdateTableModelAfterFilter); connect( m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::selectionChangedSignal, this, &AzAssetBrowserWindow::SelectionChangedSlot); @@ -251,24 +247,6 @@ void AzAssetBrowserWindow::SetExpandedAssetBrowserMode() m_assetBrowserDisplayState = AzAssetBrowser::AssetBrowserDisplayState::ExpandedMode; - disconnect( - m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this, - &AzAssetBrowserWindow::UpdateTableModelAfterFilter); - disconnect( - m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this, - &AzAssetBrowserWindow::SetTableViewVisibleAfterFilter); - - disconnect( - m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::selectionChangedSignal, this, - &AzAssetBrowserWindow::SelectionChangedSlot); - disconnect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AzAssetBrowserWindow::DoubleClickedItem); - disconnect( - m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearStringFilter, m_ui->m_searchWidget, - &AzAssetBrowser::SearchWidget::ClearStringFilter); - disconnect( - m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearTypeFilter, m_ui->m_searchWidget, - &AzAssetBrowser::SearchWidget::ClearTypeFilter); - if (m_ui->m_assetBrowserTableViewWidget->isVisible()) { m_ui->m_assetBrowserTableViewWidget->setVisible(false); @@ -281,37 +259,9 @@ void AzAssetBrowserWindow::SetDefaultAssetBrowserMode() namespace AzAssetBrowser = AzToolsFramework::AssetBrowser; m_assetBrowserDisplayState = AzAssetBrowser::AssetBrowserDisplayState::DefaultMode; - - connect( - m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this, - &AzAssetBrowserWindow::SetTableViewVisibleAfterFilter); - - connect( - m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this, - &AzAssetBrowserWindow::UpdateTableModelAfterFilter); - connect( - m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::selectionChangedSignal, this, - &AzAssetBrowserWindow::SelectionChangedSlot); - connect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AzAssetBrowserWindow::DoubleClickedItem); - connect( - m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearStringFilter, m_ui->m_searchWidget, - &AzAssetBrowser::SearchWidget::ClearStringFilter); - connect( - m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearTypeFilter, m_ui->m_searchWidget, - &AzAssetBrowser::SearchWidget::ClearTypeFilter); - - //If the filter is not empty we want to switch views and Update the model - UpdateTableModelAfterFilter(); SetTableViewVisibleAfterFilter(); } -void AzAssetBrowserWindow::UpdateTableModelAfterFilter() -{ - if (!m_ui->m_searchWidget->GetFilterString().isEmpty()) - { - m_tableModel->UpdateTableModelMaps(); - } -} void AzAssetBrowserWindow::SetTableViewVisibleAfterFilter() { @@ -389,8 +339,8 @@ void AzAssetBrowserWindow::SelectionChangedSlot(const QItemSelection& /*selected UpdatePreview(); } -// while its tempting to use Activated here, we dont actually want it to count as activation -// just becuase on some OS clicking once is activation. +// while its tempting to use Activated here, we don't actually want it to count as activation +// just because on some OS clicking once is activation. void AzAssetBrowserWindow::DoubleClickedItem([[maybe_unused]] const QModelIndex& element) { namespace AzAssetBrowser = AzToolsFramework::AssetBrowser; diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h index 753f000300..34103316ab 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h @@ -68,7 +68,6 @@ protected slots: void CreateSwitchViewMenu(); void SetExpandedAssetBrowserMode(); void SetDefaultAssetBrowserMode(); - void UpdateTableModelAfterFilter(); void SetTableViewVisibleAfterFilter(); private: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp index ec709aef8a..14c5e719b4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp @@ -24,24 +24,13 @@ namespace AzToolsFramework AZ_Assert( m_filterModel, "Error in AssetBrowserTableModel initialization, class expects source model to be an AssetBrowserFilterModel."); - connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &AssetBrowserTableModel::UpdateTableModelMaps); - connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &AssetBrowserTableModel::UpdateTableModelMaps); - connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &AssetBrowserTableModel::beginResetModel); - connect( - sourceModel, &QAbstractItemModel::modelReset, this, - [this]() - { - { - QSignalBlocker sb(this); - UpdateTableModelMaps(); - } - endResetModel(); - }); - connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &AssetBrowserTableModel::UpdateTableModelMaps); - connect(sourceModel, &QAbstractItemModel::dataChanged, this, &AssetBrowserTableModel::SourceDataChanged); - - QSortFilterProxyModel::setSourceModel(sourceModel); + + connect(m_filterModel, &QAbstractItemModel::rowsInserted, this, &AssetBrowserTableModel::UpdateTableModelMaps); + connect(m_filterModel, &QAbstractItemModel::rowsRemoved, this, &AssetBrowserTableModel::UpdateTableModelMaps); + connect(m_filterModel, &QAbstractItemModel::layoutChanged, this, &AssetBrowserTableModel::UpdateTableModelMaps); + connect(m_filterModel, &AssetBrowserFilterModel::filterChanged, this, &AssetBrowserTableModel::beginResetModel); + connect(m_filterModel, &QAbstractItemModel::dataChanged, this, &AssetBrowserTableModel::SourceDataChanged); } QModelIndex AssetBrowserTableModel::mapToSource(const QModelIndex& proxyIndex) const @@ -112,7 +101,7 @@ namespace AzToolsFramework int AssetBrowserTableModel::rowCount(const QModelIndex& parent) const { - return !parent.isValid() ? m_indexMap.size() : sourceModel()->rowCount(parent); + return !parent.isValid() ? m_indexMap.size() : 0; } int AssetBrowserTableModel::BuildTableModelMap( @@ -162,28 +151,29 @@ namespace AzToolsFramework AssetBrowserEntry* AssetBrowserTableModel::GetAssetEntry(QModelIndex index) const { - if (index.isValid()) - { - return static_cast(index.internalPointer()); - } - else + if (!index.isValid()) { AZ_Error("AssetBrowser", false, "Invalid Source Index provided to GetAssetEntry."); return nullptr; } + return static_cast(index.internalPointer()); } void AssetBrowserTableModel::UpdateTableModelMaps() { + beginResetModel(); emit layoutAboutToBeChanged(); - m_indexMap.clear(); - m_rowMap.clear(); + if (!m_indexMap.isEmpty() || !m_rowMap.isEmpty()) + { + m_indexMap.clear(); + m_rowMap.clear(); + } AzToolsFramework::EditorSettingsAPIBus::BroadcastResult( m_numberOfItemsDisplayed, &AzToolsFramework::EditorSettingsAPIBus::Handler::GetMaxNumberOfItemsShownInSearchView); - BuildTableModelMap(sourceModel()); emit layoutChanged(); + endResetModel(); } } // namespace AssetBrowser } // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h index f84e6bd81c..4048156b60 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h @@ -21,7 +21,9 @@ namespace AzToolsFramework class AssetBrowserFilterModel; class AssetBrowserEntry; - class AssetBrowserTableModel : public QSortFilterProxyModel + class AssetBrowserTableModel + : public QSortFilterProxyModel + , public AssetBrowserComponentNotificationBus::Handler { Q_OBJECT @@ -43,7 +45,7 @@ namespace AzToolsFramework int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const override; //////////////////////////////////////////////////////////////////// - private: + AssetBrowserEntry* GetAssetEntry(QModelIndex index) const; int BuildTableModelMap(const QAbstractItemModel* model, const QModelIndex& parent = QModelIndex(), int row = 0); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp index b463381638..8b58791e68 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp @@ -225,29 +225,36 @@ namespace AzToolsFramework const QModelIndex indexBelow = viewModel->index(index.row() + 1, index.column()); const QModelIndex indexAbove = viewModel->index(index.row() - 1, index.column()); - auto aboveEntry = qvariant_cast(indexBelow.data(AssetBrowserModel::Roles::EntryRole)); - auto belowEntry = qvariant_cast(indexAbove.data(AssetBrowserModel::Roles::EntryRole)); + auto belowEntry = qvariant_cast(indexBelow.data(AssetBrowserModel::Roles::EntryRole)); + auto aboveEntry = qvariant_cast(indexAbove.data(AssetBrowserModel::Roles::EntryRole)); - auto aboveSourceEntry = azrtti_cast(aboveEntry); auto belowSourceEntry = azrtti_cast(belowEntry); + auto aboveSourceEntry = azrtti_cast(aboveEntry); - // if current index is the last entry in the view - // or the index above it is a Source Entry and - // the index below is invalid or is valid but it is also a source entry - // then the current index is the only child. - if (index.row() == viewModel->rowCount() - 1 || - (indexBelow.isValid() && aboveSourceEntry && - (!indexAbove.isValid() || (indexAbove.isValid() && belowSourceEntry)))) + // Last item and the above entry is a source entry + // or indexBelow is a source entry and the index above is not + if (viewModel->rowCount() > 0 && index.row() == viewModel->rowCount() - 1) + { + if (aboveSourceEntry) + { + DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); + } + else + { + DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); + } + } + else if (belowSourceEntry && aboveSourceEntry) { DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); // Draw One Child Icon } - else if (indexBelow.isValid() && aboveSourceEntry) // The index above is a source entry + else if (belowSourceEntry && !aboveSourceEntry) { - DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); // Draw First child Icon + DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); } - else if (indexAbove.isValid() && belowSourceEntry) // The index below is a source entry + else if (aboveSourceEntry) // The index above is a source entry { - DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw Last Child Icon + DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw First Child Icon } else //the index above and below are also child entries { @@ -286,7 +293,6 @@ namespace AzToolsFramework absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathLast; break; case AzToolsFramework::AssetBrowser::EntryBranchType::OneChild: - default: absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild; break; } @@ -311,5 +317,4 @@ namespace AzToolsFramework } // namespace AssetBrowser } // namespace AzToolsFramework - #include "AssetBrowser/Views/moc_EntryDelegate.cpp" From 328cefc972bc1505f31eef1eb4355eb3182652d1 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:37:32 -0500 Subject: [PATCH 051/200] Terrain Macro Material component improvements (#4930) * First pass of non-working changes to Terrain Macro Material Component. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Reworked Terrain Macro Material to use properties instead of a material. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed comments. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * PR feedback - disable attributes when no normal map selected Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fix linux compile error - unused variables. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Signed-off-by: Gene Walters --- .../DefaultTerrainMacroMaterial.material | 8 - .../Terrain/TerrainMacroMaterial.materialtype | 63 ------ .../TerrainMacroMaterialComponent.cpp | 188 +++++++++--------- .../TerrainMacroMaterialComponent.h | 25 +-- .../EditorTerrainMacroMaterialComponent.cpp | 33 +-- .../TerrainFeatureProcessor.cpp | 65 ++---- .../TerrainRenderer/TerrainFeatureProcessor.h | 18 +- .../TerrainRenderer/TerrainMacroMaterialBus.h | 23 ++- 8 files changed, 141 insertions(+), 282 deletions(-) delete mode 100644 Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material delete mode 100644 Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype diff --git a/Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material b/Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material deleted file mode 100644 index afaf7e1947..0000000000 --- a/Gems/Terrain/Assets/Materials/Terrain/DefaultTerrainMacroMaterial.material +++ /dev/null @@ -1,8 +0,0 @@ -{ - "description": "", - "materialType": "TerrainMacroMaterial.materialtype", - "parentMaterial": "", - "propertyLayoutVersion": 1, - "properties": { - } -} diff --git a/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype b/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype deleted file mode 100644 index 17769ffb92..0000000000 --- a/Gems/Terrain/Assets/Materials/Terrain/TerrainMacroMaterial.materialtype +++ /dev/null @@ -1,63 +0,0 @@ -{ - "description": "A material for providing terrain with low-fidelity color and normals. This material will get blended with surface detail materials.", - "version": 1, - "propertyLayout": { - "groups": [ - { - "name": "baseColor", - "displayName": "Base Color", - "description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals." - }, - { - "name": "normal", - "displayName": "Normal", - "description": "Properties related to configuring surface normal." - } - ], - "properties": { - "baseColor": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Base color of the macro material", - "type": "Image" - } - ], - "normal": [ - { - "name": "textureMap", - "displayName": "Texture", - "description": "Texture for defining surface normal direction. These will override normals generated from the geometry.", - "type": "Image" - }, - { - "name": "flipX", - "displayName": "Flip X Channel", - "description": "Flip tangent direction for this normal map.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "flipY", - "displayName": "Flip Y Channel", - "description": "Flip bitangent direction for this normal map.", - "type": "Bool", - "defaultValue": false - }, - { - "name": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0 - } - ] - } - }, - "shaders": [ - ], - "functors": [ - ] -} diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp index 55653c64fa..0d161b6b2b 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp @@ -16,87 +16,65 @@ #include #include +#include + namespace Terrain { - AZ::Data::AssetId TerrainMacroMaterialConfig::s_macroMaterialTypeAssetId{}; + bool TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly() const + { + return !m_macroNormalAsset.GetId().IsValid(); + } void TerrainMacroMaterialConfig::Reflect(AZ::ReflectContext* context) { - AZ::SerializeContext* serialize = azrtti_cast(context); - if (serialize) + if (auto* serialize = azrtti_cast(context); serialize) { serialize->Class() ->Version(1) - ->Field("MacroMaterial", &TerrainMacroMaterialConfig::m_materialAsset) - ; - - // The edit context for this appears in EditorTerrainMacroMaterialComponent.cpp. - } - } - - AZ::Data::AssetId TerrainMacroMaterialConfig::GetTerrainMacroMaterialTypeAssetId() - { - // Get the Asset ID for the TerrainMacroMaterial material type and store it in a class static so that we don't have to look it - // up again. - if (!s_macroMaterialTypeAssetId.IsValid()) - { - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - s_macroMaterialTypeAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, TerrainMacroMaterialTypeAsset, - azrtti_typeid(), false); - AZ_Assert(s_macroMaterialTypeAssetId.IsValid(), "The asset '%s' couldn't be found.", TerrainMacroMaterialTypeAsset); - } - - return s_macroMaterialTypeAssetId; - } - - bool TerrainMacroMaterialConfig::IsMaterialTypeCorrect(const AZ::Data::AssetId& assetId) - { - // We'll verify that whatever material we try to load has this material type as a dependency, as a way to implicitly detect - // that we're only trying to use terrain macro materials even before we load the asset. - auto macroMaterialTypeAssetId = GetTerrainMacroMaterialTypeAssetId(); - - // Get the dependencies for the requested asset. - AZ::Outcome, AZStd::string> result; - AZ::Data::AssetCatalogRequestBus::BroadcastResult( - result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, assetId); - - // If any of the dependencies match the TerrainMacroMaterial materialtype asset, then this should be the correct type of material. - if (result) - { - for (auto& dependency : result.GetValue()) + ->Field("MacroColor", &TerrainMacroMaterialConfig::m_macroColorAsset) + ->Field("MacroNormal", &TerrainMacroMaterialConfig::m_macroNormalAsset) + ->Field("NormalFlipX", &TerrainMacroMaterialConfig::m_normalFlipX) + ->Field("NormalFlipY", &TerrainMacroMaterialConfig::m_normalFlipY) + ->Field("NormalFactor", &TerrainMacroMaterialConfig::m_normalFactor) + ; + + if (auto* editContext = serialize->GetEditContext(); editContext) { - if (dependency.m_assetId == macroMaterialTypeAssetId) - { - return true; - } + editContext + ->Class( + "Terrain Macro Material Component", "Provide a terrain macro material for a region of the world") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_macroColorAsset, "Color Texture", + "Terrain macro color texture for use by any terrain inside the bounding box on this entity.") + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_macroNormalAsset, "Normal Texture", + "Texture for defining surface normal direction. These will override normals generated from the geometry.") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_normalFlipX, "Normal Flip X", + "Flip tangent direction for this normal map.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly) + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_normalFlipY, "Normal Flip Y", + "Flip bitangent direction for this normal map.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly) + ->DataElement( + AZ::Edit::UIHandlers::Slider, &TerrainMacroMaterialConfig::m_normalFactor, "Normal Factor", + "Strength factor for scaling the normal map values.") + ->Attribute(AZ::Edit::Attributes::Min, 0.0f) + ->Attribute(AZ::Edit::Attributes::Max, 10.0f) + ->Attribute(AZ::Edit::Attributes::SoftMin, 0.0f) + ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) + ->Attribute(AZ::Edit::Attributes::ReadOnly, &TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly) + ; } } - - // Didn't have the expected dependency, so it must not be the right material type. - return false; - } - - AZ::Outcome TerrainMacroMaterialConfig::ValidateMaterialAsset(void* newValue, const AZ::Uuid& valueType) - { - if (azrtti_typeid>() != valueType) - { - AZ_Assert(false, "Unexpected value type"); - return AZ::Failure(AZStd::string("Unexpectedly received something other than a material asset for the MacroMaterial!")); - } - - auto newMaterialAsset = *static_cast*>(newValue); - - if (!IsMaterialTypeCorrect(newMaterialAsset.GetId())) - { - return AZ::Failure(AZStd::string::format( - "The selected MacroMaterial ('%s') needs to use the TerrainMacroMaterial material type.", - newMaterialAsset.GetHint().c_str())); - } - - return AZ::Success(); } - void TerrainMacroMaterialComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services) { services.push_back(AZ_CRC_CE("TerrainMacroMaterialProviderService")); @@ -133,25 +111,29 @@ namespace Terrain void TerrainMacroMaterialComponent::Activate() { - // Clear out our shape bounds and make sure the material is queued to load. + // Clear out our shape bounds and make sure the texture assets are queued to load. m_cachedShapeBounds = AZ::Aabb::CreateNull(); - m_configuration.m_materialAsset.QueueLoad(); + m_configuration.m_macroColorAsset.QueueLoad(); + m_configuration.m_macroNormalAsset.QueueLoad(); // Don't mark our material as active until it's finished loading and is valid. m_macroMaterialActive = false; - // Listen for the material asset to complete loading. - AZ::Data::AssetBus::Handler::BusConnect(m_configuration.m_materialAsset.GetId()); + // Listen for the texture assets to complete loading. + AZ::Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_macroColorAsset.GetId()); + AZ::Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_macroNormalAsset.GetId()); } void TerrainMacroMaterialComponent::Deactivate() { TerrainMacroMaterialRequestBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::Handler::BusDisconnect(); - m_configuration.m_materialAsset.Release(); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(); + m_configuration.m_macroColorAsset.Release(); + m_configuration.m_macroNormalAsset.Release(); - m_macroMaterialInstance.reset(); + m_colorImage.reset(); + m_normalImage.reset(); // Send out any notifications as appropriate based on the macro material destruction. HandleMaterialStateChange(); @@ -195,12 +177,18 @@ namespace Terrain void TerrainMacroMaterialComponent::HandleMaterialStateChange() { - // We only want our component to appear active during the time that the macro material is loaded and valid. The logic below + // We only want our component to appear active during the time that the macro material is fully loaded and valid. The logic below // will handle all transition possibilities to notify if we've become active, inactive, or just changed. We'll also only // keep a valid up-to-date copy of the shape bounds while the material is valid, since we don't need it any other time. + // Color and normal data is considered ready if it's finished loading or if we don't have a texture specified + bool colorReady = m_colorImage || (!m_configuration.m_macroColorAsset.GetId().IsValid()); + bool normalReady = m_normalImage || (!m_configuration.m_macroNormalAsset.GetId().IsValid()); + // If we don't have color or normal data, then we don't have *any* useful data, so don't activate the macro material. + bool hasAnyData = m_configuration.m_macroColorAsset.GetId().IsValid() || m_configuration.m_macroNormalAsset.GetId().IsValid(); + bool wasPreviouslyActive = m_macroMaterialActive; - bool isNowActive = (m_macroMaterialInstance != nullptr); + bool isNowActive = colorReady && normalReady && hasAnyData; // Set our state to active or inactive, based on whether or not the macro material instance is now valid. m_macroMaterialActive = isNowActive; @@ -226,9 +214,10 @@ namespace Terrain // Start listening for shape changes. LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId()); + MacroMaterialData material = GetTerrainMacroMaterialData(); + TerrainMacroMaterialNotificationBus::Broadcast( - &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialCreated, GetEntityId(), m_macroMaterialInstance, - m_cachedShapeBounds); + &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialCreated, GetEntityId(), material); } else if (wasPreviouslyActive && !isNowActive) { @@ -246,30 +235,35 @@ namespace Terrain else { // We were active both before and after, so just send out a material changed event. + MacroMaterialData material = GetTerrainMacroMaterialData(); TerrainMacroMaterialNotificationBus::Broadcast( - &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialChanged, GetEntityId(), m_macroMaterialInstance); + &TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialChanged, GetEntityId(), material); } } void TerrainMacroMaterialComponent::OnAssetReady(AZ::Data::Asset asset) { - m_configuration.m_materialAsset = asset; + if (asset.GetId() == m_configuration.m_macroColorAsset.GetId()) + { + m_configuration.m_macroColorAsset = asset; + m_colorImage = AZ::RPI::StreamingImage::FindOrCreate(m_configuration.m_macroColorAsset); - if (m_configuration.m_materialAsset.Get()->GetMaterialTypeAsset().GetId() == - TerrainMacroMaterialConfig::GetTerrainMacroMaterialTypeAssetId()) + // Clear the texture asset reference to make sure we don't prevent hot-reloading. + m_configuration.m_macroColorAsset.Release(); + } + else if (asset.GetId() == m_configuration.m_macroNormalAsset.GetId()) { - m_macroMaterialInstance = AZ::RPI::Material::FindOrCreate(m_configuration.m_materialAsset); + m_configuration.m_macroNormalAsset = asset; + m_normalImage = AZ::RPI::StreamingImage::FindOrCreate(m_configuration.m_macroNormalAsset); + + // Clear the texture asset reference to make sure we don't prevent hot-reloading. + m_configuration.m_macroColorAsset.Release(); } else { - AZ_Error("Terrain", false, "Material '%s' has the wrong material type.", m_configuration.m_materialAsset.GetHint().c_str()); - m_macroMaterialInstance.reset(); } - // Clear the material asset reference to make sure we don't prevent hot-reloading. - m_configuration.m_materialAsset.Release(); - HandleMaterialStateChange(); } @@ -278,10 +272,18 @@ namespace Terrain OnAssetReady(asset); } - void TerrainMacroMaterialComponent::GetTerrainMacroMaterialData( - AZ::Data::Instance& macroMaterial, AZ::Aabb& macroMaterialRegion) + MacroMaterialData TerrainMacroMaterialComponent::GetTerrainMacroMaterialData() { - macroMaterial = m_macroMaterialInstance; - macroMaterialRegion = m_cachedShapeBounds; + MacroMaterialData macroMaterial; + + macroMaterial.m_entityId = GetEntityId(); + macroMaterial.m_bounds = m_cachedShapeBounds; + macroMaterial.m_colorImage = m_colorImage; + macroMaterial.m_normalImage = m_normalImage; + macroMaterial.m_normalFactor = m_configuration.m_normalFactor; + macroMaterial.m_normalFlipX = m_configuration.m_normalFlipX; + macroMaterial.m_normalFlipY = m_configuration.m_normalFlipY; + + return macroMaterial; } } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h index b60f6b2a94..cd82316ff6 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.h @@ -11,10 +11,9 @@ #include #include #include -#include #include #include - +#include namespace LmbrCentral { @@ -32,23 +31,20 @@ namespace Terrain AZ_RTTI(TerrainMacroMaterialConfig, "{9DBAFFF0-FD20-4594-8884-E3266D8CCAC8}", AZ::ComponentConfig); static void Reflect(AZ::ReflectContext* context); - AZ::Data::Asset m_materialAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; - - static AZ::Data::AssetId GetTerrainMacroMaterialTypeAssetId(); - static bool IsMaterialTypeCorrect(const AZ::Data::AssetId&); - AZ::Outcome ValidateMaterialAsset(void* newValue, const AZ::Uuid& valueType); - - private: - static inline constexpr const char* TerrainMacroMaterialTypeAsset = "materials/terrain/terrainmacromaterial.azmaterialtype"; - static AZ::Data::AssetId s_macroMaterialTypeAssetId; + bool NormalMapAttributesAreReadOnly() const; + AZ::Data::Asset m_macroColorAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; + AZ::Data::Asset m_macroNormalAsset = { AZ::Data::AssetLoadBehavior::QueueLoad }; + bool m_normalFlipX = false; + bool m_normalFlipY = false; + float m_normalFactor = 1.0f; }; class TerrainMacroMaterialComponent : public AZ::Component , public TerrainMacroMaterialRequestBus::Handler , private LmbrCentral::ShapeComponentNotificationsBus::Handler - , private AZ::Data::AssetBus::Handler + , private AZ::Data::AssetBus::MultiHandler { public: template @@ -70,7 +66,7 @@ namespace Terrain bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override; bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override; - void GetTerrainMacroMaterialData(AZ::Data::Instance& macroMaterial, AZ::Aabb& macroMaterialRegion) override; + MacroMaterialData GetTerrainMacroMaterialData() override; private: //////////////////////////////////////////////////////////////////////// @@ -86,7 +82,8 @@ namespace Terrain TerrainMacroMaterialConfig m_configuration; AZ::Aabb m_cachedShapeBounds; - AZ::Data::Instance m_macroMaterialInstance; bool m_macroMaterialActive{ false }; + AZ::Data::Instance m_colorImage; + AZ::Data::Instance m_normalImage; }; } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp index 07472d1b85..65500af42d 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/EditorComponents/EditorTerrainMacroMaterialComponent.cpp @@ -17,36 +17,7 @@ namespace Terrain { BaseClassType::ReflectSubClass( context, 1, - &LmbrCentral::EditorWrappedComponentBaseVersionConverter - ); - - AZ::SerializeContext* serializeContext = azrtti_cast(context); - - if (serializeContext) - { - AZ::EditContext* editContext = serializeContext->GetEditContext(); - - // The edit context for TerrainMacroMaterialConfig is specified here to make it easier to add custom filtering to the - // asset picker for the material asset so that we can eventually only display materials that inherit from the proper - // material type. - if (editContext) - { - editContext - ->Class( - "Terrain Macro Material Component", "Provide a terrain macro material for a region of the world") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - - ->DataElement( - AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_materialAsset, "Macro Material", - "Terrain macro material for use by any terrain inside the bounding box on this entity.") - // This is disabled until ChangeValidate can support the Asset type. :( - //->Attribute(AZ::Edit::Attributes::ChangeValidate, &TerrainMacroMaterialConfig::ValidateMaterialAsset) - ; - } - } - + &LmbrCentral::EditorWrappedComponentBaseVersionConverter< + typename BaseClassType::WrappedComponentType, typename BaseClassType::WrappedConfigType, 1>); } } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index 8c85e21490..e6aed28897 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -51,13 +51,6 @@ namespace Terrain { // Terrain material static const char* const HeightmapImage("settings.heightmapImage"); - - // Macro material - static const char* const MacroColorTextureMap("baseColor.textureMap"); - static const char* const MacroNormalTextureMap("normal.textureMap"); - static const char* const MacroNormalFlipX("normal.flipX"); - static const char* const MacroNormalFlipY("normal.flipY"); - static const char* const MacroNormalFactor("normal.factor"); } namespace ShaderInputs @@ -185,12 +178,11 @@ namespace Terrain m_areaData.m_heightmapUpdated = true; } - void TerrainFeatureProcessor::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, MaterialInstance material, const AZ::Aabb& region) + void TerrainFeatureProcessor::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& newMaterialData) { MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId); - materialData.m_bounds = region; - UpdateMacroMaterialData(materialData, material); + UpdateMacroMaterialData(materialData, newMaterialData); // Update all sectors in region. ForOverlappingSectors(materialData.m_bounds, @@ -203,20 +195,14 @@ namespace Terrain ); } - void TerrainFeatureProcessor::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, MaterialInstance macroMaterial) + void TerrainFeatureProcessor::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& newMaterialData) { - if (macroMaterial) - { - MacroMaterialData& data = FindOrCreateMacroMaterial(entityId); - UpdateMacroMaterialData(data, macroMaterial); - } - else - { - RemoveMacroMaterial(entityId); - } + MacroMaterialData& data = FindOrCreateMacroMaterial(entityId); + UpdateMacroMaterialData(data, newMaterialData); } - void TerrainFeatureProcessor::OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) + void TerrainFeatureProcessor::OnTerrainMacroMaterialRegionChanged( + AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) { MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId); for (SectorData& sectorData : m_sectorData) @@ -269,6 +255,7 @@ namespace Terrain } m_areaData.m_macroMaterialsUpdated = true; + RemoveMacroMaterial(entityId); } void TerrainFeatureProcessor::UpdateTerrainData() @@ -382,42 +369,18 @@ namespace Terrain TerrainMacroMaterialRequestBus::EnumerateHandlers( [&](TerrainMacroMaterialRequests* handler) { - MaterialInstance macroMaterial; - AZ::Aabb bounds; - handler->GetTerrainMacroMaterialData(macroMaterial, bounds); + MacroMaterialData macroMaterial = handler->GetTerrainMacroMaterialData(); AZ::EntityId entityId = *(Terrain::TerrainMacroMaterialRequestBus::GetCurrentBusId()); - OnTerrainMacroMaterialCreated(entityId, macroMaterial, bounds); + OnTerrainMacroMaterialCreated(entityId, macroMaterial); return true; } ); TerrainMacroMaterialNotificationBus::Handler::BusConnect(); } - void TerrainFeatureProcessor::UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, MaterialInstance material) + void TerrainFeatureProcessor::UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, const MacroMaterialData& newMaterialData) { - // Since we're using an actual macro material instance for now, get the values from it that we care about. - const auto materialLayout = material->GetMaterialPropertiesLayout(); - - const AZ::RPI::MaterialPropertyIndex macroColorTextureMapIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroColorTextureMap)); - AZ_Error(TerrainFPName, macroColorTextureMapIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroColorTextureMap); - - const AZ::RPI::MaterialPropertyIndex macroNormalTextureMapIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalTextureMap)); - AZ_Error(TerrainFPName, macroNormalTextureMapIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalTextureMap); - - const AZ::RPI::MaterialPropertyIndex macroNormalFlipXIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFlipX)); - AZ_Error(TerrainFPName, macroNormalFlipXIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFlipX); - - const AZ::RPI::MaterialPropertyIndex macroNormalFlipYIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFlipY)); - AZ_Error(TerrainFPName, macroNormalFlipYIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFlipY); - - const AZ::RPI::MaterialPropertyIndex macroNormalFactorIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFactor)); - AZ_Error(TerrainFPName, macroNormalFactorIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFactor); - - macroMaterialData.m_colorImage = material->GetPropertyValue(macroColorTextureMapIndex).GetValue>(); - macroMaterialData.m_normalImage = material->GetPropertyValue(macroNormalTextureMapIndex).GetValue>(); - macroMaterialData.m_normalFlipX = material->GetPropertyValue(macroNormalFlipXIndex).GetValue(); - macroMaterialData.m_normalFlipY = material->GetPropertyValue(macroNormalFlipYIndex).GetValue(); - macroMaterialData.m_normalFactor = material->GetPropertyValue(macroNormalFactorIndex).GetValue(); + macroMaterialData = newMaterialData; if (macroMaterialData.m_bounds.IsValid()) { @@ -783,7 +746,7 @@ namespace Terrain // larger but this will limit how much is rendered. } - TerrainFeatureProcessor::MacroMaterialData* TerrainFeatureProcessor::FindMacroMaterial(AZ::EntityId entityId) + MacroMaterialData* TerrainFeatureProcessor::FindMacroMaterial(AZ::EntityId entityId) { for (MacroMaterialData& data : m_macroMaterials.GetDataVector()) { @@ -795,7 +758,7 @@ namespace Terrain return nullptr; } - TerrainFeatureProcessor::MacroMaterialData& TerrainFeatureProcessor::FindOrCreateMacroMaterial(AZ::EntityId entityId) + MacroMaterialData& TerrainFeatureProcessor::FindOrCreateMacroMaterial(AZ::EntityId entityId) { MacroMaterialData* dataPtr = FindMacroMaterial(entityId); if (dataPtr != nullptr) diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h index d9f15f2d47..f82fd8ecb0 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h @@ -112,18 +112,6 @@ namespace Terrain AZStd::fixed_vector m_macroMaterials; }; - struct MacroMaterialData - { - AZ::EntityId m_entityId; - AZ::Aabb m_bounds = AZ::Aabb::CreateNull(); - - AZ::Data::Instance m_colorImage; - AZ::Data::Instance m_normalImage; - bool m_normalFlipX{ false }; - bool m_normalFlipY{ false }; - float m_normalFactor{ 0.0f }; - }; - // AZ::RPI::MaterialReloadNotificationBus::Handler overrides... void OnMaterialReinitialized(const MaterialInstance& material) override; @@ -132,8 +120,8 @@ namespace Terrain void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override; // TerrainMacroMaterialNotificationBus overrides... - void OnTerrainMacroMaterialCreated(AZ::EntityId entityId, MaterialInstance material, const AZ::Aabb& region) override; - void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, MaterialInstance material) override; + void OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& material) override; + void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& material) override; void OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override; void OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) override; @@ -143,7 +131,7 @@ namespace Terrain void UpdateTerrainData(); void PrepareMaterialData(); - void UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, MaterialInstance material); + void UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, const MacroMaterialData& newMaterialData); void ProcessSurfaces(const FeatureProcessor::RenderPacket& process); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h index c0618a7f66..af1e755b32 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMacroMaterialBus.h @@ -12,11 +12,22 @@ #include #include #include - -#include +#include namespace Terrain { + struct MacroMaterialData + { + AZ::EntityId m_entityId; + AZ::Aabb m_bounds = AZ::Aabb::CreateNull(); + + AZ::Data::Instance m_colorImage; + AZ::Data::Instance m_normalImage; + bool m_normalFlipX{ false }; + bool m_normalFlipY{ false }; + float m_normalFactor{ 0.0f }; + }; + /** * Request terrain macro material data. */ @@ -32,7 +43,7 @@ namespace Terrain virtual ~TerrainMacroMaterialRequests() = default; // Get the terrain macro material and the region that it covers. - virtual void GetTerrainMacroMaterialData(AZ::Data::Instance& macroMaterial, AZ::Aabb& macroMaterialRegion) = 0; + virtual MacroMaterialData GetTerrainMacroMaterialData() = 0; }; using TerrainMacroMaterialRequestBus = AZ::EBus; @@ -51,14 +62,12 @@ namespace Terrain virtual void OnTerrainMacroMaterialCreated( [[maybe_unused]] AZ::EntityId macroMaterialEntity, - [[maybe_unused]] AZ::Data::Instance macroMaterial, - [[maybe_unused]] const AZ::Aabb& macroMaterialRegion) + [[maybe_unused]] const MacroMaterialData& macroMaterial) { } virtual void OnTerrainMacroMaterialChanged( - [[maybe_unused]] AZ::EntityId macroMaterialEntity, - [[maybe_unused]] AZ::Data::Instance macroMaterial) + [[maybe_unused]] AZ::EntityId macroMaterialEntity, [[maybe_unused]] const MacroMaterialData& macroMaterial) { } From b4f42b599af5f218597511cdd8ba95feedf36f0a Mon Sep 17 00:00:00 2001 From: LesaelR <89800757+LesaelR@users.noreply.github.com> Date: Mon, 25 Oct 2021 10:05:07 -0700 Subject: [PATCH 052/200] Adding Shaderball test and asset files. (#4743) Signed-off-by: Rosario Cox Signed-off-by: Gene Walters --- .../_dev_shaderball_00_basecolor.png | 3 + .../assets/ShaderBall/shaderball.dbgsg | 3111 +++++++++++++++++ .../assets/ShaderBall/shaderball.fbx | 3 + .../assetpipeline/fbx_tests/fbx_tests.py | 209 +- 4 files changed, 3235 insertions(+), 91 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/_dev_shaderball_00_basecolor.png create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.dbgsg create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.fbx diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/_dev_shaderball_00_basecolor.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/_dev_shaderball_00_basecolor.png new file mode 100644 index 0000000000..415ca3e521 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/_dev_shaderball_00_basecolor.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93a7e033d9fb0fcac221647322bde03716643d789390f79078c4fcc37ecfd005 +size 68327 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.dbgsg new file mode 100644 index 0000000000..7d070fcea0 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.dbgsg @@ -0,0 +1,3111 @@ +ProductName: shaderball.dbgsg +debugSceneGraphVersion: 1 +shaderball +Node Name: RootNode +Node Path: RootNode +Node Type: RootBoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, 1.000000, 0.000000> + BasisZ: < 0.000000, 0.000000, 1.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: ShaderBall_1m +Node Path: RootNode.ShaderBall_1m +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: transform +Node Path: RootNode.ShaderBall_1m.transform +Node Type: TransformData + Matrix: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InnerPortion +Node Path: RootNode.ShaderBall_1m.InnerPortion +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: MaterialBase +Node Path: RootNode.ShaderBall_1m.MaterialBase +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InlayRings +Node Path: RootNode.ShaderBall_1m.InlayRings +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: MainSphere +Node Path: RootNode.ShaderBall_1m.MainSphere +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: HubCap_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1 +Node Type: MeshData + Positions: Count 20476. Hash: 5411361036988924549 + Normals: Count 20476. Hash: 5915154682063029054 + FaceList: Count 8676. Hash: 9142863582186575896 + FaceMaterialIds: Count 8676. Hash: 723360536895379791 + +Node Name: HubCap_2 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: HubCap_1_optimized +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized +Node Type: MeshData + Positions: Count 4724. Hash: 448283466401665158 + Normals: Count 4724. Hash: 345267294337234954 + FaceList: Count 8676. Hash: 11155608373229651496 + FaceMaterialIds: Count 8676. Hash: 723360536895379791 + +Node Name: InnerSphere_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1 +Node Type: MeshData + Positions: Count 19800. Hash: 17342106809405761922 + Normals: Count 19800. Hash: 602384960091561079 + FaceList: Count 9800. Hash: 15975352410309879244 + FaceMaterialIds: Count 9800. Hash: 2219364576630417284 + +Node Name: InnerSphere_2 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InnerSphere_1_optimized +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized +Node Type: MeshData + Positions: Count 5846. Hash: 18229431498904963984 + Normals: Count 5846. Hash: 12980164457801827192 + FaceList: Count 9800. Hash: 2914108932212582430 + FaceMaterialIds: Count 9800. Hash: 2219364576630417284 + +Node Name: InnerCone_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1 +Node Type: MeshData + Positions: Count 192. Hash: 3022774266117638288 + Normals: Count 192. Hash: 12863565187316537150 + FaceList: Count 64. Hash: 1255131899577053537 + FaceMaterialIds: Count 64. Hash: 6312841653578246165 + +Node Name: InnerCone_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InnerCone_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized +Node Type: MeshData + Positions: Count 65. Hash: 832325255726840940 + Normals: Count 65. Hash: 14121159448916141450 + FaceList: Count 64. Hash: 9660474080562375138 + FaceMaterialIds: Count 64. Hash: 6312841653578246165 + +Node Name: InnerPost_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1 +Node Type: MeshData + Positions: Count 4864. Hash: 7530018531436061848 + Normals: Count 4864. Hash: 534420091635424803 + FaceList: Count 2432. Hash: 4330575616942580147 + FaceMaterialIds: Count 2432. Hash: 12393250111858627709 + +Node Name: InnerPost_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InnerPost_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized +Node Type: MeshData + Positions: Count 1300. Hash: 15277132209442728123 + Normals: Count 1300. Hash: 1247055552073340932 + FaceList: Count 2432. Hash: 16808521883586752319 + FaceMaterialIds: Count 2432. Hash: 12393250111858627709 + +Node Name: InnerBaseCuff_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1 +Node Type: MeshData + Positions: Count 4096. Hash: 1814004361979755447 + Normals: Count 4096. Hash: 1760582409511017750 + FaceList: Count 2048. Hash: 6642755656211284824 + FaceMaterialIds: Count 2048. Hash: 2795877824940392899 + +Node Name: InnerBaseCuff_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InnerBaseCuff_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized +Node Type: MeshData + Positions: Count 1122. Hash: 15009434720129565864 + Normals: Count 1122. Hash: 7245598986723209052 + FaceList: Count 2048. Hash: 2887888015166354330 + FaceMaterialIds: Count 2048. Hash: 2795877824940392899 + +Node Name: Inset_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1 +Node Type: MeshData + Positions: Count 1536. Hash: 6247721054948161820 + Normals: Count 1536. Hash: 16362051041722971623 + FaceList: Count 768. Hash: 3142075668387852387 + FaceMaterialIds: Count 768. Hash: 2979441869813298271 + +Node Name: Inset_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: Inset_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized +Node Type: MeshData + Positions: Count 448. Hash: 9520190263881589378 + Normals: Count 448. Hash: 8658432920439039136 + FaceList: Count 768. Hash: 8621713142583851338 + FaceMaterialIds: Count 768. Hash: 2979441869813298271 + +Node Name: BottomCap_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1 +Node Type: MeshData + Positions: Count 960. Hash: 13502046855286963834 + Normals: Count 960. Hash: 7165134632415312413 + FaceList: Count 448. Hash: 11458684524699877690 + FaceMaterialIds: Count 448. Hash: 15444662993354423801 + +Node Name: BottomCap_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: BottomCap_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized +Node Type: MeshData + Positions: Count 257. Hash: 6437758550313952689 + Normals: Count 257. Hash: 9382966961287919705 + FaceList: Count 448. Hash: 16093592375171717669 + FaceMaterialIds: Count 448. Hash: 15444662993354423801 + +Node Name: InnerCushion_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1 +Node Type: MeshData + Positions: Count 54208. Hash: 17548679297809443982 + Normals: Count 54208. Hash: 18279651495381460361 + FaceList: Count 27104. Hash: 12714006452420198903 + FaceMaterialIds: Count 27104. Hash: 12674758055018775830 + +Node Name: InnerCushion_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: InnerCushion_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized +Node Type: MeshData + Positions: Count 13860. Hash: 15965614532178328362 + Normals: Count 13860. Hash: 7297376140184766040 + FaceList: Count 27104. Hash: 2523751700832022798 + FaceMaterialIds: Count 27104. Hash: 12674758055018775830 + +Node Name: OuterBaseCuff_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1 +Node Type: MeshData + Positions: Count 20048. Hash: 3861768905934340307 + Normals: Count 20048. Hash: 12292053423401502106 + FaceList: Count 10024. Hash: 4821138438569111218 + FaceMaterialIds: Count 10024. Hash: 9849297365743356453 + +Node Name: OuterBaseCuff_2 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: OuterBaseCuff_1_optimized +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized +Node Type: MeshData + Positions: Count 5206. Hash: 5201932106801476439 + Normals: Count 5206. Hash: 15696187265416627056 + FaceList: Count 10024. Hash: 10907381836011223214 + FaceMaterialIds: Count 10024. Hash: 9849297365743356453 + +Node Name: RingLeft_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1 +Node Type: MeshData + Positions: Count 2560. Hash: 10944366330558725569 + Normals: Count 2560. Hash: 11471590896496428199 + FaceList: Count 1280. Hash: 2548580276766813978 + FaceMaterialIds: Count 1280. Hash: 6371267399123018661 + +Node Name: RingLeft_2 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: RingLeft_1_optimized +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized +Node Type: MeshData + Positions: Count 720. Hash: 14374869925777029719 + Normals: Count 720. Hash: 2252820527750115179 + FaceList: Count 1280. Hash: 17583744445000895264 + FaceMaterialIds: Count 1280. Hash: 6371267399123018661 + +Node Name: RingRight_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1 +Node Type: MeshData + Positions: Count 2560. Hash: 17639843025153488175 + Normals: Count 2560. Hash: 8564843488923790338 + FaceList: Count 1280. Hash: 2548580276766813978 + FaceMaterialIds: Count 1280. Hash: 6371267399123018661 + +Node Name: RingRight_2 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: RingRight_1_optimized +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized +Node Type: MeshData + Positions: Count 720. Hash: 17033597990859129189 + Normals: Count 720. Hash: 14263134585377771060 + FaceList: Count 1280. Hash: 13824345071081010014 + FaceMaterialIds: Count 1280. Hash: 6371267399123018661 + +Node Name: RightHub_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1 +Node Type: MeshData + Positions: Count 6304. Hash: 11021385291123971383 + Normals: Count 6304. Hash: 10267084099841111837 + FaceList: Count 3152. Hash: 17728162485525521181 + FaceMaterialIds: Count 3152. Hash: 17405713692885844041 + +Node Name: RightHub_2 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: RightHub_1_optimized +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized +Node Type: MeshData + Positions: Count 1617. Hash: 9820946434895369083 + Normals: Count 1617. Hash: 16951123277321747448 + FaceList: Count 3152. Hash: 15437295155178226041 + FaceMaterialIds: Count 3152. Hash: 17405713692885844041 + +Node Name: LeftHub_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1 +Node Type: MeshData + Positions: Count 6304. Hash: 7564731352768958355 + Normals: Count 6304. Hash: 8133714814490222392 + FaceList: Count 3152. Hash: 17728162485525521181 + FaceMaterialIds: Count 3152. Hash: 17405713692885844041 + +Node Name: LeftHub_2 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: LeftHub_1_optimized +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized +Node Type: MeshData + Positions: Count 1617. Hash: 8811470420139443913 + Normals: Count 1617. Hash: 11224729257132823435 + FaceList: Count 3152. Hash: 16696390019846851737 + FaceMaterialIds: Count 3152. Hash: 17405713692885844041 + +Node Name: Inside_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1 +Node Type: MeshData + Positions: Count 3520. Hash: 13476777876937219698 + Normals: Count 3520. Hash: 10561277746451021236 + FaceList: Count 1760. Hash: 1345243954764462275 + FaceMaterialIds: Count 1760. Hash: 3100204266221257056 + +Node Name: Inside_2 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: Inside_1_optimized +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized +Node Type: MeshData + Positions: Count 960. Hash: 1074011803485396393 + Normals: Count 960. Hash: 16318911598614464642 + FaceList: Count 1760. Hash: 3382287220404120115 + FaceMaterialIds: Count 1760. Hash: 3100204266221257056 + +Node Name: MainOuterSphere_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1 +Node Type: MeshData + Positions: Count 18912. Hash: 15956257973657753552 + Normals: Count 18912. Hash: 9328348641512406334 + FaceList: Count 9456. Hash: 9836933646038198686 + FaceMaterialIds: Count 9456. Hash: 13982281543095132650 + +Node Name: MainOuterSphere_2 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_2 +Node Type: BoneData + WorldTransform: + BasisX: < 1.000000, 0.000000, 0.000000> + BasisY: < 0.000000, -0.000000, 1.000000> + BasisZ: < 0.000000, -1.000000, -0.000000> + Transl: < 0.000000, 0.000000, 0.000000> + +Node Name: MainOuterSphere_1_optimized +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized +Node Type: MeshData + Positions: Count 4891. Hash: 9579089515723090907 + Normals: Count 4891. Hash: 10089610259011330329 + FaceList: Count 9456. Hash: 13541126452398082145 + FaceMaterialIds: Count 9456. Hash: 13982281543095132650 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 20476. Hash: 10688945422788452939 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 20476. Hash: 1387390223232454000 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 20476. Hash: 4424021631256816544 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 20476. Hash: 9768152532901400557 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 20476. Hash: 4890305528292926235 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 20476. Hash: 309820643999247955 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 20476. Hash: 10688945422788452939 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 20476. Hash: 1387390223232454000 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 4724. Hash: 10265340188340999982 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 4724. Hash: 6393506322209434620 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 4724. Hash: 7072046838448900487 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 4724. Hash: 14469479861311642848 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 4724. Hash: 14586570136206675867 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 4724. Hash: 1080930468361041453 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.HubCap.HubCap_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 19800. Hash: 9998270082112342253 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 19800. Hash: 715698668253946311 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 19800. Hash: 9689144294054390217 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 19800. Hash: 13129471596255615133 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 19800. Hash: 12915864712175384367 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 19800. Hash: 704744783983559605 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 19800. Hash: 9998270082112342253 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 19800. Hash: 715698668253946311 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 5846. Hash: 2128276120164603588 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 5846. Hash: 954788723450394678 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 5846. Hash: 14309642535096835998 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 5846. Hash: 2996000735336843208 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 5846. Hash: 6423899825309547347 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 5846. Hash: 6861847030641362531 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InnerPortion.InnerSphere.InnerSphere_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 192. Hash: 10645867109602892598 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 192. Hash: 7257961874201179082 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 192. Hash: 12720324392877726426 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 192. Hash: 7937958557505694755 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 192. Hash: 15065829696130008213 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 192. Hash: 14378088137727336097 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 192. Hash: 10645867109602892598 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 192. Hash: 7257961874201179082 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 65. Hash: 3145658351065228323 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 65. Hash: 13102825703658386866 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 65. Hash: 14651886668877289638 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 65. Hash: 7706988068999921308 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 65. Hash: 1183045102730537867 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 65. Hash: 15200278891890596008 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCone.InnerCone_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 4864. Hash: 5283498994389857134 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 4864. Hash: 4759806696539235318 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 4864. Hash: 1916980755154570809 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 4864. Hash: 3641075817419129841 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 4864. Hash: 1597884606887295389 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 4864. Hash: 12470368568863176335 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 4864. Hash: 5283498994389857134 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 4864. Hash: 4759806696539235318 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 1300. Hash: 519927422840758162 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 1300. Hash: 16690819534142395524 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 1300. Hash: 13697492049473980098 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 1300. Hash: 16069718749273082363 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 1300. Hash: 9503213552298852479 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 1300. Hash: 14920629477034919393 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerPost.InnerPost_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 4096. Hash: 12344372623177285558 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 4096. Hash: 3415525735687273566 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 4096. Hash: 1937219152553164558 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 4096. Hash: 16718347243549159919 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 4096. Hash: 7775661729866538946 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 4096. Hash: 16465645522600859391 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 4096. Hash: 12344372623177285558 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 4096. Hash: 3415525735687273566 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 1122. Hash: 10794215007683911939 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 1122. Hash: 4030215540982392192 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 1122. Hash: 14289595630739500233 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 1122. Hash: 13010448485976282215 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 1122. Hash: 8318401526835048407 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 1122. Hash: 100095329364523248 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerBaseCuff.InnerBaseCuff_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 1536. Hash: 7123339701675171032 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 1536. Hash: 15827204344457762670 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 1536. Hash: 15732245908985477324 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 1536. Hash: 865397990859725823 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 1536. Hash: 2552281640891423471 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 1536. Hash: 17779645716491562667 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 1536. Hash: 7123339701675171032 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 1536. Hash: 15827204344457762670 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 448. Hash: 11533511688039530581 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 448. Hash: 6463578982826635244 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 448. Hash: 10590255987412720146 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 448. Hash: 17744412650281038495 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 448. Hash: 8278337182397882868 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 448. Hash: 8818080862566813062 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.Inset.Inset_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 960. Hash: 12059380739436291361 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 960. Hash: 17894062399627363441 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 960. Hash: 3025207993250150716 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 960. Hash: 909667023812047269 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 960. Hash: 9807712812840041710 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 960. Hash: 15826838159231044203 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 960. Hash: 12059380739436291361 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 960. Hash: 17894062399627363441 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 257. Hash: 8823641736072761245 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 257. Hash: 17988941723121644388 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 257. Hash: 8180735114915510878 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 257. Hash: 6608315278879931556 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 257. Hash: 15606348252975307518 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 257. Hash: 9909736394462106525 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.BottomCap.BottomCap_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 54208. Hash: 3444203649101035485 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 54208. Hash: 937532470362399061 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 54208. Hash: 196567085853229565 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 54208. Hash: 1716600532837684655 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 54208. Hash: 2905235470236164097 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 54208. Hash: 2074363216216487237 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 54208. Hash: 3444203649101035485 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 54208. Hash: 937532470362399061 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 13860. Hash: 263381874971540959 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 13860. Hash: 15191673020616208011 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 13860. Hash: 7105458185902008309 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 13860. Hash: 16259705089531364237 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 13860. Hash: 16022317673583270139 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 13860. Hash: 7251784463761381809 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.InnerCushion.InnerCushion_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 20048. Hash: 10464397683020008867 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 20048. Hash: 11067273583889078226 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 20048. Hash: 15901168792190323178 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 20048. Hash: 552570814640404138 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 20048. Hash: 17726428588184726937 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 20048. Hash: 7508591493894188819 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 20048. Hash: 10464397683020008867 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 20048. Hash: 11067273583889078226 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 5206. Hash: 1074257132915638034 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 5206. Hash: 2243653809093009497 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 5206. Hash: 11559777087289074275 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 5206. Hash: 15450183130901763011 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 5206. Hash: 15359221084106995089 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 5206. Hash: 8652443944286435468 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MaterialBase.OuterBaseCuff.OuterBaseCuff_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 14931201357194905697 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 5600314145323623005 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 2560. Hash: 11738661055172304644 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 2560. Hash: 320620113692599118 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 2560. Hash: 8466587534284734762 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 2560. Hash: 3318206549561696188 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 14931201357194905697 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 5600314145323623005 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 720. Hash: 75483450873662317 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 720. Hash: 3793407172213641704 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 720. Hash: 2508676912793167321 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 720. Hash: 2013136453053212946 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 720. Hash: 9302779689053257196 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 720. Hash: 16922723248982534245 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingLeft.RingLeft_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 9568588494434360329 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 5573555818259644549 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 2560. Hash: 12082144485035076372 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 2560. Hash: 5616878210949329467 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 2560. Hash: 4057154333260499171 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 2560. Hash: 1620460765416970456 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 9568588494434360329 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 2560. Hash: 5573555818259644549 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 720. Hash: 3542867785718437760 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 720. Hash: 5575788853295372734 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 720. Hash: 8244955966647049157 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 720. Hash: 17763430282605007327 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 720. Hash: 5442657821959315522 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 720. Hash: 12477592739739533067 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.InlayRings.RingRight.RingRight_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 4609122246850169975 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 2696528076485355457 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 6304. Hash: 6640465288865380105 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 6304. Hash: 133343330720363387 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 6304. Hash: 790774688340154169 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 6304. Hash: 3046294637431015510 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 4609122246850169975 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 2696528076485355457 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 1617. Hash: 16761061667647714654 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 1617. Hash: 14954885971875692232 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 1617. Hash: 37061345418264916 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 1617. Hash: 7368059604555723833 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 1617. Hash: 6244533771017459078 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 1617. Hash: 6416015160247779547 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.RightHub.RightHub_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 2524875548439506384 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 89810986084680009 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 6304. Hash: 1044733215619569246 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 6304. Hash: 15252409165383740719 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 6304. Hash: 3184716392697283856 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 6304. Hash: 4969210758291089995 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 2524875548439506384 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 6304. Hash: 89810986084680009 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 1617. Hash: 8467946356718878053 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 1617. Hash: 2373603727160338558 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 1617. Hash: 1521191693628786862 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 1617. Hash: 7175852234718691900 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 1617. Hash: 12283058591680528758 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 1617. Hash: 14516337485055158228 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.LeftHub.LeftHub_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 3520. Hash: 7734180808251274182 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 3520. Hash: 13560118186140352568 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 3520. Hash: 5538036360908204376 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 3520. Hash: 470358662493460341 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 3520. Hash: 13801426056203770982 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 3520. Hash: 8463107387658894201 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 3520. Hash: 7734180808251274182 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 3520. Hash: 13560118186140352568 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 960. Hash: 2691029117997309291 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 960. Hash: 10093724573967674240 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 960. Hash: 1221219959437752888 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 960. Hash: 1294720383009806722 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 960. Hash: 10294793677923893113 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 960. Hash: 6108415656799664788 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.Inside.Inside_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.Tiled +Node Type: MeshVertexUVData + UVs: Count 18912. Hash: 4120783891454032649 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 18912. Hash: 9011003754405408275 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 18912. Hash: 12406712159692783345 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 18912. Hash: 7868083933985729169 + GenerationMethod: 1 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 18912. Hash: 1990603474898794477 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 18912. Hash: 4812378464029296668 + GenerationMethod: 1 + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_2.Tiled +Node Type: MeshVertexUVData + UVs: Count 18912. Hash: 4120783891454032649 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_2.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 18912. Hash: 9011003754405408275 + UVCustomName: Unwrapped + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_2.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + +Node Name: Tiled +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.Tiled +Node Type: MeshVertexUVData + UVs: Count 4891. Hash: 15498889522919365505 + UVCustomName: Tiled + +Node Name: Unwrapped +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.Unwrapped +Node Type: MeshVertexUVData + UVs: Count 4891. Hash: 15832520573612498718 + UVCustomName: Unwrapped + +Node Name: TangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.TangentSet_0 +Node Type: MeshVertexTangentData + Tangents: Count 4891. Hash: 6697133368486369688 + GenerationMethod: 1 + SetIndex: 0 + +Node Name: TangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.TangentSet_1 +Node Type: MeshVertexTangentData + Tangents: Count 4891. Hash: 18420832496569008358 + GenerationMethod: 1 + SetIndex: 1 + +Node Name: BitangentSet_0 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.BitangentSet_0 +Node Type: MeshVertexBitangentData + Bitangents: Count 4891. Hash: 2267250201584370787 + GenerationMethod: 1 + +Node Name: BitangentSet_1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.BitangentSet_1 +Node Type: MeshVertexBitangentData + Bitangents: Count 4891. Hash: 7889928104085840247 + GenerationMethod: 1 + +Node Name: blinn1 +Node Path: RootNode.ShaderBall_1m.MainSphere.MainOuterSphere.MainOuterSphere_1_optimized.blinn1 +Node Type: MaterialData + MaterialName: blinn1 + UniqueId: 2076548245838624187 + IsNoDraw: false + DiffuseColor: < 0.800000, 0.800000, 0.800000> + SpecularColor: < 0.500000, 0.500000, 0.500000> + EmissiveColor: < 0.000000, 0.000000, 0.000000> + Opacity: 1.000000 + Shininess: 6.311791 + UseColorMap: Not set + BaseColor: Not set + UseMetallicMap: Not set + MetallicFactor: Not set + UseRoughnessMap: Not set + RoughnessFactor: Not set + UseEmissiveMap: Not set + EmissiveIntensity: Not set + UseAOMap: Not set + DiffuseTexture: ShaderBall/_dev_shaderball_00_basecolor.png + SpecularTexture: + BumpTexture: + NormalTexture: + MetallicTexture: + RoughnessTexture: + AmbientOcclusionTexture: + EmissiveTexture: + BaseColorTexture: ShaderBall/_dev_shaderball_00_basecolor.png + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.fbx new file mode 100644 index 0000000000..caf6dcbe8f --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e63a55a35c749a16a03e10a1f53a48bd426c61db80151de080235b14cf6b70d +size 2479344 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py index 71f200074c..5965db57b1 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py @@ -21,8 +21,8 @@ from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture from ..ap_fixtures.ap_config_backup_fixture import ap_config_backup_fixture as ap_config_backup_fixture -from ..ap_fixtures.ap_config_default_platform_fixture import ap_config_default_platform_fixture as ap_config_default_platform_fixture - +from ..ap_fixtures.ap_config_default_platform_fixture \ + import ap_config_default_platform_fixture as ap_config_default_platform_fixture # Import LyShared import ly_test_tools.o3de.pipeline_utils as utils @@ -33,6 +33,7 @@ logger = logging.getLogger(__name__) # Helper: variables we will use for parameter values in the test: targetProjects = ["AutomatedTesting"] + @pytest.fixture @pytest.mark.SUITE_sandbox def local_resources(request, workspace, ap_setup_fixture): @@ -54,21 +55,21 @@ class BlackboxAssetTest: blackbox_fbx_tests = [ pytest.param( BlackboxAssetTest( - test_name= "OneMeshOneMaterial_RunAP_SuccessWithMatchingProducts", - asset_folder= "OneMeshOneMaterial", + test_name="OneMeshOneMaterial_RunAP_SuccessWithMatchingProducts", + asset_folder="OneMeshOneMaterial", scene_debug_file="onemeshonematerial.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "OneMeshOneMaterial.fbx", - uuid = b"8a9164adb84859be893e18aa819438e1", - jobs = [ + source_file_name="OneMeshOneMaterial.fbx", + uuid=b"8a9164adb84859be893e18aa819438e1", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", + job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=1, - products = [ + products=[ asset_db_utils.DBProduct( product_name='onemeshonematerial/onemeshonematerial.dbgsg', sub_id=1918494907, @@ -86,21 +87,21 @@ blackbox_fbx_tests = [ BlackboxAssetTest( # Verifies that the soft naming convention feature with level of detail meshes works. # https://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer-soft-naming.html - test_name= "SoftNamingLOD_RunAP_SuccessWithMatchingProducts", - asset_folder= "SoftNamingLOD", + test_name="SoftNamingLOD_RunAP_SuccessWithMatchingProducts", + asset_folder="SoftNamingLOD", scene_debug_file="lodtest.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "lodtest.fbx", - uuid = b"44c8627fe2c25aae91fe3ff9547be3b9", - jobs = [ + source_file_name="lodtest.fbx", + uuid=b"44c8627fe2c25aae91fe3ff9547be3b9", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", + job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=22, - products = [ + products=[ asset_db_utils.DBProduct( product_name='softnaminglod/lodtest.dbgsg', sub_id=-632012261, @@ -118,21 +119,21 @@ blackbox_fbx_tests = [ BlackboxAssetTest( # Verifies that the soft naming convention feature with physics proxies works. # https://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer-soft-naming.html - test_name= "SoftNamingPhysics_RunAP_SuccessWithMatchingProducts", - asset_folder= "SoftNamingPhysics", + test_name="SoftNamingPhysics_RunAP_SuccessWithMatchingProducts", + asset_folder="SoftNamingPhysics", scene_debug_file="physicstest.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "physicstest.fbx", - uuid = b"df957b7918cf5b029806c73f630fa1c8", - jobs = [ + source_file_name="physicstest.fbx", + uuid=b"df957b7918cf5b029806c73f630fa1c8", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", + job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=14, - products = [ + products=[ asset_db_utils.DBProduct( product_name='softnamingphysics/physicstest.dbgsg', sub_id=-740411732, @@ -152,21 +153,21 @@ blackbox_fbx_tests = [ ), pytest.param( BlackboxAssetTest( - test_name= "MultipleMeshOneMaterial_RunAP_SuccessWithMatchingProducts", - asset_folder= "TwoMeshOneMaterial", + test_name="MultipleMeshOneMaterial_RunAP_SuccessWithMatchingProducts", + asset_folder="TwoMeshOneMaterial", scene_debug_file="multiple_mesh_one_material.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "multiple_mesh_one_material.fbx", - uuid = b"597618fd497659a1b197a015fe47aa95", - jobs = [ + source_file_name="multiple_mesh_one_material.fbx", + uuid=b"597618fd497659a1b197a015fe47aa95", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", + job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=2, - products = [ + products=[ asset_db_utils.DBProduct( product_name='twomeshonematerial/multiple_mesh_one_material.dbgsg', sub_id=2077268018, @@ -183,22 +184,22 @@ blackbox_fbx_tests = [ pytest.param( BlackboxAssetTest( # Verifies whether multiple meshes can share linked materials - test_name= "MultipleMeshLinkedMaterials_RunAP_SuccessWithMatchingProducts", - asset_folder= "TwoMeshLinkedMaterials", - scene_debug_file= "multiple_mesh_linked_materials.dbgsg", - assets = [ + test_name="MultipleMeshLinkedMaterials_RunAP_SuccessWithMatchingProducts", + asset_folder="TwoMeshLinkedMaterials", + scene_debug_file="multiple_mesh_linked_materials.dbgsg", + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "multiple_mesh_linked_materials.fbx", - uuid = b"25d8301c2eef5dc7bded310db8ea608d", - jobs = [ + source_file_name="multiple_mesh_linked_materials.fbx", + uuid=b"25d8301c2eef5dc7bded310db8ea608d", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", - platform= "pc", + job_key="Scene compilation", + platform="pc", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=2, - products= [ + products=[ asset_db_utils.DBProduct( product_name='twomeshlinkedmaterials/multiple_mesh_linked_materials.dbgsg', sub_id=-1898461950, @@ -216,22 +217,22 @@ blackbox_fbx_tests = [ pytest.param( BlackboxAssetTest( # Verifies a mesh with multiple materials - test_name= "SingleMeshMultipleMaterials_RunAP_SuccessWithMatchingProducts", - asset_folder= "OneMeshMultipleMaterials", + test_name="SingleMeshMultipleMaterials_RunAP_SuccessWithMatchingProducts", + asset_folder="OneMeshMultipleMaterials", scene_debug_file="single_mesh_multiple_materials.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "single_mesh_multiple_materials.fbx", - uuid = b"f08fd585dfa35881b4bf86637da5e858", - jobs = [ + source_file_name="single_mesh_multiple_materials.fbx", + uuid=b"f08fd585dfa35881b4bf86637da5e858", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", - platform= "pc", + job_key="Scene compilation", + platform="pc", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=1, - products = [ + products=[ asset_db_utils.DBProduct( product_name='onemeshmultiplematerials/single_mesh_multiple_materials.dbgsg', sub_id=-262822238, @@ -277,21 +278,21 @@ blackbox_fbx_tests = [ ), pytest.param( BlackboxAssetTest( - test_name= "MotionTest_RunAP_SuccessWithMatchingProducts", - asset_folder= "Motion", + test_name="MotionTest_RunAP_SuccessWithMatchingProducts", + asset_folder="Motion", scene_debug_file="Jack_Idle_Aim_ZUp.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "Jack_Idle_Aim_ZUp.fbx", - uuid = b"eda904ae0e145f8b973d57fc5809918b", - jobs = [ + source_file_name="Jack_Idle_Aim_ZUp.fbx", + uuid=b"eda904ae0e145f8b973d57fc5809918b", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", + job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=0, - products = [ + products=[ asset_db_utils.DBProduct( product_name='motion/jack_idle_aim_zup.dbgsg', sub_id=-517610290, @@ -307,29 +308,56 @@ blackbox_fbx_tests = [ ] ), ), + pytest.param( + BlackboxAssetTest( + test_name="ShaderBall_RunAP_SuccessWithMatchingProducts", + asset_folder="ShaderBall", + scene_debug_file="shaderball.dbgsg", + assets=[ + asset_db_utils.DBSourceAsset( + source_file_name="shaderball.fbx", + uuid=b"48181ba8038e5193997540fc8dffb06d", + jobs=[ + asset_db_utils.DBJob( + job_key="Scene compilation", + builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", + status=4, + error_count=0, + warning_count=30, + products=[ + asset_db_utils.DBProduct( + product_name='shaderball/shaderball.dbgsg', + sub_id=-1607815784, + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + ] + ), + ] + ) + ] + ), + ), ] - blackbox_fbx_special_tests = [ pytest.param( BlackboxAssetTest( - test_name= "MultipleMeshMultipleMaterial_MultipleAssetInfo_RunAP_SuccessWithMatchingProducts", - asset_folder= "TwoMeshTwoMaterial", - override_asset_folder = "OverrideAssetInfoForTwoMeshTwoMaterial", + test_name="MultipleMeshMultipleMaterial_MultipleAssetInfo_RunAP_SuccessWithMatchingProducts", + asset_folder="TwoMeshTwoMaterial", + override_asset_folder="OverrideAssetInfoForTwoMeshTwoMaterial", scene_debug_file="multiple_mesh_multiple_material.dbgsg", override_scene_debug_file="multiple_mesh_multiple_material_override.dbgsg", - assets = [ + assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "multiple_mesh_multiple_material.fbx", - uuid = b"b5915fb874af5c8a866ccabbddb57595", - jobs = [ + source_file_name="multiple_mesh_multiple_material.fbx", + uuid=b"b5915fb874af5c8a866ccabbddb57595", + jobs=[ asset_db_utils.DBJob( job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=2, - products = [ + products=[ asset_db_utils.DBProduct( product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg', sub_id=896980093, @@ -341,16 +369,16 @@ blackbox_fbx_special_tests = [ ], override_assets=[ asset_db_utils.DBSourceAsset( - source_file_name = "multiple_mesh_multiple_material.fbx", - uuid = b"b5915fb874af5c8a866ccabbddb57595", - jobs = [ + source_file_name="multiple_mesh_multiple_material.fbx", + uuid=b"b5915fb874af5c8a866ccabbddb57595", + jobs=[ asset_db_utils.DBJob( - job_key= "Scene compilation", + job_key="Scene compilation", builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3", status=4, error_count=0, warning_count=2, - products = [ + products=[ asset_db_utils.DBProduct( product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg', sub_id=896980093, @@ -378,29 +406,26 @@ class TestsFBX_AllPlatforms(object): @pytest.mark.BAT @pytest.mark.SUITE_sandbox @pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests) - def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace, - ap_setup_fixture, asset_processor, project, - blackbox_param): + def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace, ap_setup_fixture, + asset_processor, project, blackbox_param): """ - Please see run_fbx_test(...) for details + Please see run_fbx_test(...) for details Test Steps: 1. Determine if blackbox is set to none 2. Run FBX Test + """ if blackbox_param == None: return - self.run_fbx_test(workspace, ap_setup_fixture, - asset_processor, project, blackbox_param) + self.run_fbx_test(workspace, ap_setup_fixture, asset_processor, project, blackbox_param) @pytest.mark.BAT @pytest.mark.SUITE_sandbox @pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests) - def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self, - workspace, ap_setup_fixture, - asset_processor, project, - blackbox_param): + def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts( + self, workspace, ap_setup_fixture, asset_processor, project, blackbox_param): """ Please see run_fbx_test(...) for details @@ -430,7 +455,7 @@ class TestsFBX_AllPlatforms(object): + product.product_name def run_fbx_test(self, workspace, ap_setup_fixture, asset_processor, - project, blackbox_params: BlackboxAssetTest, overrideAsset = False): + project, blackbox_params: BlackboxAssetTest, overrideAsset=False): """ These tests work by having the test case ingest the test data and determine the run pattern. Tests will process scene settings files and will additionally do a verification against a provided debug file @@ -469,21 +494,23 @@ class TestsFBX_AllPlatforms(object): expected_product_list.append(expected_product.product_name) missing_assets, _ = utils.compare_assets_with_cache(expected_product_list, - asset_processor.project_test_cache_folder()) + asset_processor.project_test_cache_folder()) - assert not missing_assets, f'The following assets were expected to be in, but not found in cache: {str(missing_assets)}' + assert not missing_assets, \ + f'The following assets were expected to be in, but not found in cache: {str(missing_assets)}' # Load the asset database. db_path = os.path.join(asset_processor.temp_asset_root(), "Cache", "assetdb.sqlite") cache_root = os.path.dirname(os.path.join(asset_processor.temp_asset_root(), "Cache", - ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform])) + ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform])) if blackbox_params.scene_debug_file: - scene_debug_file = blackbox_params.override_scene_debug_file if overrideAsset\ + scene_debug_file = blackbox_params.override_scene_debug_file if overrideAsset \ else blackbox_params.scene_debug_file - debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(), blackbox_params.scene_debug_file) + debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(), + blackbox_params.scene_debug_file) expected_debug_graph_path = os.path.join(asset_processor.project_test_source_folder(), scene_debug_file) logger.info(f"Parsing scene graph: {debug_graph_path}") From b31d47e91fc524c2408fe333c8b40a74aac65211 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 25 Oct 2021 10:07:55 -0700 Subject: [PATCH 053/200] ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface (#4739) * ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface Introduced new PassSystemInterface::ForEachPass() funtion to replace PassSystemInterface::FindPasses(), PassSystemInterface::GetPassesByTemplateName and ParentPass::FindPassByNameRecursive() functions. Update all the places which were using those three functions. The new pass finding filter support any combination of pass name, pass template name, pass class type, pass hirechary, owner scene, owner render pipeline. Update unit tests. Signed-off-by: Qing Tao Signed-off-by: Gene Walters --- .../Include/Atom/Feature/ImGui/ImGuiUtils.h | 6 +- .../Include/Atom/Feature/ImGui/SystemBus.h | 7 +- .../Atom/Feature/Utils/FrameCaptureBus.h | 2 +- .../DirectionalLightFeatureProcessor.cpp | 71 +++-- ...fuseGlobalIlluminationFeatureProcessor.cpp | 61 +++-- .../DiffuseProbeGridFeatureProcessor.cpp | 12 +- .../DisplayMapper/DisplayMapperPass.cpp | 25 +- .../Source/FrameCaptureSystemComponent.cpp | 37 +-- .../Source/ImGui/ImGuiSystemComponent.cpp | 48 ++-- .../Code/Source/ImGui/ImGuiSystemComponent.h | 2 +- .../DepthOfField/DepthOfFieldSettings.cpp | 20 +- .../ExposureControlSettings.cpp | 29 +- .../LookModificationCompositePass.cpp | 14 +- .../PostProcessing/SMAAFeatureProcessor.cpp | 51 ++-- .../ProfilingCaptureSystemComponent.cpp | 31 +-- .../Source/ProfilingCaptureSystemComponent.h | 2 - .../ReflectionCopyFrameBufferPass.cpp | 19 +- .../ReflectionScreenSpaceBlurPass.cpp | 2 +- .../ReflectionScreenSpaceCompositePass.cpp | 26 +- .../ProjectedShadowFeatureProcessor.cpp | 54 ++-- .../Shadows/ProjectedShadowFeatureProcessor.h | 4 +- .../SkinnedMeshFeatureProcessor.cpp | 13 +- .../SkinnedMesh/SkinnedMeshFeatureProcessor.h | 2 +- .../Include/Atom/RPI.Public/Pass/ParentPass.h | 3 - .../Code/Include/Atom/RPI.Public/Pass/Pass.h | 4 + .../Include/Atom/RPI.Public/Pass/PassFilter.h | 150 +++++------ .../Atom/RPI.Public/Pass/PassLibrary.h | 4 +- .../Include/Atom/RPI.Public/Pass/PassSystem.h | 4 +- .../RPI.Public/Pass/PassSystemInterface.h | 23 +- .../Source/RPI.Public/Pass/ParentPass.cpp | 23 -- .../RPI/Code/Source/RPI.Public/Pass/Pass.cpp | 5 + .../Source/RPI.Public/Pass/PassFilter.cpp | 247 +++++++++++++++--- .../Source/RPI.Public/Pass/PassLibrary.cpp | 82 ++++-- .../Source/RPI.Public/Pass/PassSystem.cpp | 20 +- Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp | 159 +++++++++-- .../Code/Rendering/HairFeatureProcessor.cpp | 44 ++-- .../Code/Rendering/HairFeatureProcessor.h | 2 + 37 files changed, 787 insertions(+), 521 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h index a200f30c98..52e272a9c4 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/ImGuiUtils.h @@ -50,12 +50,12 @@ namespace AZ return scope; } - //! Sets the active context based on the provided PassHierarchyFilter. If the filter doesn't match exactly one pass, then do nothing. - static ImGuiActiveContextScope FromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) + //! Sets the active context based on the provided pass hierarchy filter. If the filter doesn't match exactly one pass, then do nothing. + static ImGuiActiveContextScope FromPass(const AZStd::vector& passHierarchy) { ImGuiActiveContextScope scope; scope.ConnectToImguiNotificationBus(); - ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchyFilter); + ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchy); return scope; } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h index 289cb178d4..78f71b39ba 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/ImGui/SystemBus.h @@ -15,11 +15,6 @@ namespace AZ { - namespace RPI - { - class PassHierarchyFilter; - } - namespace Render { class ImGuiPass; @@ -51,7 +46,7 @@ namespace AZ //! Pushes whichever ImGui pass is default on the top of the active context stack. Returns true/false for success/fail. virtual bool PushActiveContextFromDefaultPass() = 0; //! Pushes whichever ImGui pass is provided in passHierarchy on the top of the active context stack. Returns true/false for success/fail. - virtual bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) = 0; + virtual bool PushActiveContextFromPass(const AZStd::vector& passHierarchy) = 0; //! Pops the active context off the top of the active context stack. Returns true if there's a context to pop. virtual bool PopActiveContext() = 0; //! Gets the context at the top of the active context stack. Returns nullptr if the stack is emtpy. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h index 93600ec08f..c80926700e 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/FrameCaptureBus.h @@ -50,7 +50,7 @@ namespace AZ virtual bool CaptureScreenshotWithPreview(const AZStd::string& outputFilePath) = 0; //! Save a buffer attachment or a image attachment binded to a pass's slot to a data file. - //! @param passHierarchy For finding the pass by using PassHierarchyFilter + //! @param passHierarchy For finding the pass by using a pass hierarchy filter. Check PassFilter::CreateWithPassHierarchy() function for detail //! @param slotName Name of the pass's slot. The attachment bound to this slot will be captured. //! @param option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state //! and use PassAttachmentReadbackOption::Output to capture the output state diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 6c24b7d35b..b6c6910fd3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -647,54 +647,46 @@ namespace AZ UpdateViewsOfCascadeSegments(); } - void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() { - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("CascadedShadowmapsTemplate")); + void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() + { m_cascadedShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("CascadedShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { + RPI::RenderPipeline* pipeline = pass->GetRenderPipeline(); const RPI::RenderPipelineId pipelineId = pipeline->GetId(); - // This function can be called when the pipeline is not attached to the scene. - // So we check it is attached to the scene. - if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) + + CascadedShadowmapsPass* shadowPass = azrtti_cast(pass); + AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); + if (pipeline->GetDefaultView()) { - CascadedShadowmapsPass* shadowPass = azrtti_cast(pass); - AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); - if (pipeline->GetDefaultView()) - { - m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); - } + m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass() { - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); m_esmShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - const RPI::RenderPipelineId pipelineId = pipeline->GetId(); - // checking the render pipeline is just removed from the scene. - if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) + const RPI::RenderPipelineId pipelineId = pass->GetRenderPipeline()->GetId(); + + if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) { - if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) + EsmShadowmapsPass* esmPass = azrtti_cast(pass); + AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); + if (esmPass->GetLightTypeName() == m_lightTypeName) { - EsmShadowmapsPass* esmPass = azrtti_cast(pass); - AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); - if (m_cascadedShadowmapsPasses.find(esmPass->GetRenderPipeline()->GetId()) != m_cascadedShadowmapsPasses.end() && - esmPass->GetLightTypeName() == m_lightTypeName) - { - m_esmShadowmapsPasses[pipelineId].push_back(esmPass); - } + m_esmShadowmapsPasses[pipelineId].push_back(esmPass); } } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DirectionalLightFeatureProcessor::PrepareCameraViews() @@ -1063,12 +1055,13 @@ namespace AZ // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, // to filter out shadows from objects that are excluded from the cubemap - RPI::PassClassFilter passFilter; - AZStd::vector cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!cubeMapPasses.empty()) - { - usageFlags |= RPI::View::UsageReflectiveCubeMap; - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + usageFlags |= RPI::View::UsageReflectiveCubeMap; + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); segment.m_view = RPI::View::CreateView(viewName, usageFlags); } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp index c085b26e31..453dbbc0ab 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationFeatureProcessor.cpp @@ -80,35 +80,48 @@ namespace AZ } // update the size multiplier on the DiffuseProbeGridDownsamplePass output - AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; - RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy); - const AZStd::vector& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter); - for (RPI::Pass* pass : downsamplePasses) + // NOTE: The ownerScene wasn't added to both filters. This is because the passes from the non-owner scene may have invalid SRG values which could lead to + // GPU error if the scene doesn't have this feature processor enabled. + // For example, the ASV MultiScene sample may have TDR. { - for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) - { - RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; - RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; - - sizeMultipliers.m_widthMultiplier = sizeMultiplier; - sizeMultipliers.m_heightMultiplier = sizeMultiplier; - } - - // set the output scale on the PassSrg - RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); - auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale")); - downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + AZStd::vector downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; + RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy); + RPI::PassSystemInterface::Get()->ForEachPass( + downsamplePassFilter, + [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) + { + RPI::Ptr outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; + RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; + + sizeMultipliers.m_widthMultiplier = sizeMultiplier; + sizeMultipliers.m_heightMultiplier = sizeMultiplier; + } + + // set the output scale on the PassSrg + RPI::FullscreenTrianglePass* downsamplePass = static_cast(pass); + RHI::ShaderInputNameIndex outputImageScaleShaderInput = "m_outputImageScale"; + downsamplePass->GetShaderResourceGroup()->SetConstant( + outputImageScaleShaderInput, aznumeric_cast(1.0f / sizeMultiplier)); + + // handle all downsample passes + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } // update the image scale on the DiffuseComposite pass - AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; - RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy); - const AZStd::vector& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter); - for (RPI::Pass* pass : compositePasses) { - RPI::FullscreenTrianglePass* compositePass = static_cast(pass); - auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale")); - compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast(1.0f / sizeMultiplier)); + AZStd::vector compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") }; + RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy); + RPI::PassSystemInterface::Get()->ForEachPass(compositePassFilter, [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + RPI::FullscreenTrianglePass* compositePass = static_cast(pass); + RHI::ShaderInputNameIndex imageScaleShaderInput = "m_imageScale"; + compositePass->GetShaderResourceGroup()->SetConstant(imageScaleShaderInput, aznumeric_cast(1.0f / sizeMultiplier)); + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } } } // namespace Render diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index 4329fd556c..5ea4748fc9 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -603,12 +603,12 @@ namespace AZ RHI::Ptr device = RHI::RHISystemInterface::Get()->GetDevice(); if (device->GetFeatures().m_rayTracing == false) { - RPI::PassHierarchyFilter updatePassFilter(AZ::Name("DiffuseProbeGridUpdatePass")); - const AZStd::vector& updatePasses = RPI::PassSystemInterface::Get()->FindPasses(updatePassFilter); - for (RPI::Pass* pass : updatePasses) - { - pass->SetEnabled(false); - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(false); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp index 3ec8840a1c..5b5599383e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DisplayMapper/DisplayMapperPass.cpp @@ -10,9 +10,10 @@ #include #include #include -#include +#include #include #include +#include #include #include #include @@ -66,22 +67,14 @@ namespace AZ { // Need to invalidate the CopyToSwapChain pass so that it updates the pipeline state in the event that // the swapchain format changed (for example, moving from LDR to HDR display) - auto* passSystem = RPI::PassSystemInterface::Get(); - const Name fullscreenCopyTemplateName("FullscreenCopyTemplate"); - - if (passSystem->HasPassesForTemplateName(fullscreenCopyTemplateName)) - { - const AZStd::vector& passes = passSystem->GetPassesForTemplateName(fullscreenCopyTemplateName); - for (RPI::Pass* pass : passes) + const Name copyToSwapChainPassName("CopyToSwapChain"); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(copyToSwapChainPassName, GetRenderPipeline()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - RPI::FullscreenTrianglePass* fullscreenTrianglePass = azrtti_cast(pass); - const Name& passName = fullscreenTrianglePass->GetName(); - if (passName.GetStringView() == "CopyToSwapChain") - { - fullscreenTrianglePass->QueueForInitialization(); - } - } - } + pass->QueueForInitialization(); + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); + ConfigureDisplayParameters(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index 8c0360dec2..ed2d8a1d9f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -372,29 +372,25 @@ namespace AZ } m_latestCaptureInfo.clear(); - // Find the pass first - RPI::PassClassFilter passFilter; - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - - if (foundPasses.size() == 0) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter)); + if (!previewPass) { - AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass pass "); + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass"); return false; } - AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast(foundPasses[0]); bool result = previewPass->ReadbackOutput(m_readback); if (result) { m_state = State::Pending; m_result = FrameCaptureResult::None; SystemTickBus::Handler::BusConnect(); + return true; } - else - { - AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");; - } - return result; + + AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass"); + return false; } bool FrameCaptureSystemComponent::CapturePassAttachment(const AZStd::vector& passHierarchy, const AZStd::string& slot, @@ -405,6 +401,12 @@ namespace AZ return false; } + if (passHierarchy.size() == 0) + { + AZ_Warning("FrameCaptureSystemComponent", false, "Empty data in passHierarchy"); + return false; + } + InitReadback(); if (m_state != State::Idle) @@ -426,17 +428,15 @@ namespace AZ } m_latestCaptureInfo.clear(); - // Find the pass first - AZ::RPI::PassHierarchyFilter passFilter(passHierarchy); - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchy); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); - if (foundPasses.size() == 0) + if (!pass) { - AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passHierarchy[0].c_str()); return false; } - AZ::RPI::Pass* pass = foundPasses[0]; if (pass->ReadbackAttachment(m_readback, Name(slot), option)) { m_state = State::Pending; @@ -444,6 +444,7 @@ namespace AZ SystemTickBus::Handler::BusConnect(); return true; } + AZ_Warning("FrameCaptureSystemComponent", false, "Failed to readback the attachment bound to pass [%s] slot [%s]", pass->GetName().GetCStr(), slot.c_str()); return false; } diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp index afca20c5cb..3783752e67 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.cpp @@ -109,15 +109,15 @@ namespace AZ void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func) { ImGuiContext* contextToRestore = ImGui::GetCurrentContext(); - RPI::PassClassFilter filter; - auto imguiPasses = RPI::PassSystemInterface::Get()->FindPasses(filter); - - for (RPI::Pass* pass : imguiPasses) - { - ImGuiPass* imguiPass = azrtti_cast(pass); - ImGui::SetCurrentContext(imguiPass->GetContext()); - func(imguiPass); - } + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + ImGuiPass* imguiPass = azrtti_cast(pass); + ImGui::SetCurrentContext(imguiPass->GetContext()); + func(imguiPass); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); ImGui::SetCurrentContext(contextToRestore); } @@ -169,29 +169,37 @@ namespace AZ return false; } - bool ImGuiSystemComponent::PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) + bool ImGuiSystemComponent::PushActiveContextFromPass(const AZStd::vector& passHierarchyFilter) { - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passHierarchyFilter); + if (passHierarchyFilter.size() == 0) + { + AZ_Warning("ImGuiSystemComponent", false, "passHierarchyFilter is empty"); + return false; + } + AZStd::vector foundImGuiPasses; - for (RPI::Pass* pass : foundPasses) - { - ImGuiPass* imGuiPass = azrtti_cast(pass); - if (imGuiPass) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - foundImGuiPasses.push_back(imGuiPass); - } - } + ImGuiPass* imGuiPass = azrtti_cast(pass); + if (imGuiPass) + { + foundImGuiPasses.push_back(imGuiPass); + } + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); if (foundImGuiPasses.size() == 0) { - AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter.ToString().c_str()); + AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter[0].c_str()); return false; } if (foundImGuiPasses.size() > 1) { - AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter.ToString().c_str()); + AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter[0].c_str()); } ImGuiContext* context = foundImGuiPasses.at(0)->GetContext(); diff --git a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h index 838cf0b3c2..d59124890f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ImGui/ImGuiSystemComponent.h @@ -56,7 +56,7 @@ namespace AZ ImGuiPass* GetDefaultImGuiPass() override; bool PushActiveContextFromDefaultPass() override; - bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) override; + bool PushActiveContextFromPass(const AZStd::vector& passHierarchy) override; bool PopActiveContext() override; ImGuiContext* GetActiveContext() override; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp index fe1ce8a281..98b527868d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/DepthOfField/DepthOfFieldSettings.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -259,24 +260,19 @@ namespace AZ // [GFX TODO][ATOM-3035]This function is temporary and will change with improvement to the draw list tag system void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled) - { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); + { const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate"); - if (passSystem->HasPassesForTemplateName(TemplateNameReadBackFocusDepth)) - { - const AZStd::vector& dofPasses = passSystem->GetPassesForTemplateName(TemplateNameReadBackFocusDepth); - for (RPI::Pass* pass : dofPasses) + // [GFX TODO][ATOM-4908] multiple camera should be distingushed. + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(TemplateNameReadBackFocusDepth, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, enabled](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* dofPass = azrtti_cast(pass); - // Check this pass belongs to a render pipeline of the scene. - // [GFX TODO][ATOM-4908] multiple camera should be distingushed. - const RPI::RenderPipelineId pipelineId = dofPass->GetRenderPipeline()->GetId(); - if (enabled && GetParentScene()->GetRenderPipeline(pipelineId)) + if (enabled) { m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus(); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId) diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp index 96ca424307..26c2a61d54 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcess/ExposureControl/ExposureControlSettings.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -188,21 +189,21 @@ namespace AZ void ExposureControlSettings::UpdateLuminanceHeatmap() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - // [GFX-TODO][ATOM-13194] Support multiple views for the luminance heatmap - // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass - const RPI::Ptr luminanceHeatmap = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHeatmapNameId); - if (luminanceHeatmap) - { - luminanceHeatmap->SetEnabled(m_heatmapEnabled); - } - - const RPI::Ptr histogramGenerator = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHistogramGeneratorNameId); - if (histogramGenerator) - { - histogramGenerator->SetEnabled(m_heatmapEnabled); - } + // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass + RPI::PassFilter heatmapPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHeatmapNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(heatmapPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(m_heatmapEnabled); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + RPI::PassFilter histogramPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHistogramGeneratorNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(histogramPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + pass->SetEnabled(m_heatmapEnabled); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void ExposureControlSettings::UpdateBuffer() diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp index 85c45de96b..aac3d1d941 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/LookModificationCompositePass.cpp @@ -31,12 +31,14 @@ namespace AZ 0, [](const uint8_t& value) { - auto passes = RPI::PassSystem::Get()->FindPasses(RPI::PassClassFilter()); - for (auto* pass : passes) - { - LookModificationCompositePass* lookModPass = azrtti_cast(pass); - lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); - } + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass(); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [value](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + LookModificationCompositePass* lookModPass = azrtti_cast(pass); + lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); + + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); }, ConsoleFunctorFlags::Null, "This can be increased to deal with particularly tricky luts. Range (0-2). 0 (default) - Standard linear sampling. 1 - 7 tap b-spline sampling. 2 - 19 tap b-spline sampling." diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp index eef0c51e95..ad059fbec0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/SMAAFeatureProcessor.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -71,26 +72,18 @@ namespace AZ void SMAAFeatureProcessor::UpdateConvertToPerceptualPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId)) - { - const AZStd::vector& convertToPerceptualColorPasses = passSystem->GetPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId); - for (RPI::Pass* pass : convertToPerceptualColorPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_convertToPerceptualColorPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { pass->SetEnabled(m_data.m_enable); - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateEdgeDetectionPass() - { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_edgeDetectioPassTemplateNameId)) - { - const AZStd::vector& edgeDetectionPasses = passSystem->GetPassesForTemplateName(m_edgeDetectioPassTemplateNameId); - for (RPI::Pass* pass : edgeDetectionPasses) + { + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_edgeDetectioPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* edgeDetectionPass = azrtti_cast(pass); @@ -106,18 +99,14 @@ namespace AZ edgeDetectionPass->SetPredicationScale(m_data.m_predicationScale); edgeDetectionPass->SetPredicationStrength(m_data.m_predicationStrength); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateBlendingWeightCalculationPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId)) - { - const AZStd::vector& blendingWeightCalculationPasses = passSystem->GetPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId); - for (RPI::Pass* pass : blendingWeightCalculationPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_blendingWeightCalculationPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* blendingWeightCalculationPass = azrtti_cast(pass); @@ -130,18 +119,14 @@ namespace AZ blendingWeightCalculationPass->SetDiagonalDetectionEnable(m_data.m_enableDiagonalDetection); blendingWeightCalculationPass->SetCornerDetectionEnable(m_data.m_enableCornerDetection); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::UpdateNeighborhoodBlendingPass() { - auto* passSystem = AZ::RPI::PassSystemInterface::Get(); - - if (passSystem->HasPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId)) - { - const AZStd::vector& neighborhoodBlendingPasses = passSystem->GetPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId); - for (RPI::Pass* pass : neighborhoodBlendingPasses) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_neighborhoodBlendingPassTemplateNameId, GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { auto* neighborhoodBlendingPass = azrtti_cast(pass); @@ -153,8 +138,8 @@ namespace AZ { neighborhoodBlendingPass->SetOutputMode(SMAAOutputMode::PassThrough); } - } - } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet) diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index 66adfe9985..9bfb2b7e9e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -377,14 +377,7 @@ namespace AZ bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath) { - // Find the root pass. - AZStd::vector passes = FindPasses({ "Root" }); - if (passes.empty()) - { - return false; - } - - RPI::Pass* root = passes[0]; + RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get(); // Enable all the Timestamp queries in passes. root->SetTimestampQueryEnabled(true); @@ -465,14 +458,7 @@ namespace AZ bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath) { - // Find the root pass. - AZStd::vector passes = FindPasses({ "Root" }); - if (passes.empty()) - { - return false; - } - - RPI::Pass* root = passes[0]; + RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get(); // Enable all the PipelineStatistics queries in passes. root->SetPipelineStatisticsQueryEnabled(true); @@ -572,19 +558,6 @@ namespace AZ return passes; } - AZStd::vector ProfilingCaptureSystemComponent::FindPasses(AZStd::vector&& passHierarchy) const - { - // Find the pass first. - RPI::PassHierarchyFilter passFilter(passHierarchy); - AZStd::vector foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (foundPasses.size() == 0) - { - AZ_Warning("ProfilingCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); - } - - return foundPasses; - } - void ProfilingCaptureSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) { // Update the delayed captures diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h index a9bb8c585f..af1d2f5643 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.h @@ -78,8 +78,6 @@ namespace AZ // Recursively collect all the passes from the root pass. AZStd::vector CollectPassesRecursively(const RPI::Pass* root) const; - AZStd::vector FindPasses(AZStd::vector&& passHierarchy) const; - DelayedQueryCaptureHelper m_timestampCapture; DelayedQueryCaptureHelper m_cpuFrameTimeStatisticsCapture; DelayedQueryCaptureHelper m_pipelineStatisticsCapture; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp index 37b1885ee3..a1858a7e9d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp @@ -28,16 +28,17 @@ namespace AZ void ReflectionCopyFrameBufferPass::BuildInternal() { - RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!passes.empty()) - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); - Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); + Data::Instance& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment(); - RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); - AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); - } + RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); + AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); + + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); FullscreenTrianglePass::BuildInternal(); } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp index 394a6fd406..edd7ad1013 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.cpp @@ -150,7 +150,7 @@ namespace AZ auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT); RPI::PassAttachment* transientPassAttachment = aznew RPI::PassAttachment(); - AZStd::string transientAttachmentName = AZStd::string::format("ReflectionScreenSpace_BlurImage%d", mip); + AZStd::string transientAttachmentName = AZStd::string::format("%s.ReflectionScreenSpace_BlurImage%d", GetPathName().GetCStr(), mip); transientPassAttachment->m_name = transientAttachmentName; transientPassAttachment->m_path = transientAttachmentName; transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp index 1cf227650c..1362191691 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp @@ -33,20 +33,22 @@ namespace AZ return; } - RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); - const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); - if (!passes.empty()) - { - Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline()); - // compute the max mip level based on the available mips in the previous frame image, and capping it - // to stay within a range that has reasonable data - const uint32_t MaxNumRoughnessMips = 8; - uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(pass); - auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); - m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); - } + // compute the max mip level based on the available mips in the previous frame image, and capping it + // to stay within a range that has reasonable data + const uint32_t MaxNumRoughnessMips = 8; + uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + + auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); + m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); + + return RPI::PassFilterExecutionFlow::StopVisitingPasses; + }); FullscreenTrianglePass::CompileResources(context); } diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 7c0b3563c7..70ccaa5702 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -313,52 +313,38 @@ namespace AZ::Render void ProjectedShadowFeatureProcessor::CachePasses() { - const AZStd::vector validPipelineIds = CacheProjectedShadowmapsPass(); - CacheEsmShadowmapsPass(validPipelineIds); + CacheProjectedShadowmapsPass(); + CacheEsmShadowmapsPass(); m_shadowmapPassNeedsUpdate = true; } - AZStd::vector ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() + void ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() { - const AZStd::vector& renderPipelines = GetParentScene()->GetRenderPipelines(); - const auto* passSystem = RPI::PassSystemInterface::Get();; - const AZStd::vector& passes = passSystem->GetPassesForTemplateName(Name("ProjectedShadowmapsTemplate")); - - AZStd::vector validPipelineIds; m_projectedShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - ProjectedShadowmapsPass* shadowPass = static_cast(pass); - for (const RPI::RenderPipelinePtr& pipeline : renderPipelines) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ProjectedShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - if (pipeline.get() == shadowPass->GetRenderPipeline()) - { - m_projectedShadowmapsPasses.emplace_back(shadowPass); - validPipelineIds.push_back(shadowPass->GetRenderPipeline()->GetId()); - } - } - } - return validPipelineIds; + ProjectedShadowmapsPass* shadowPass = static_cast(pass); + m_projectedShadowmapsPasses.emplace_back(shadowPass); + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } - void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds) + void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass() { const Name LightTypeName = Name("projected"); - - const auto* passSystem = RPI::PassSystemInterface::Get(); - const AZStd::vector passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate")); - + m_esmShadowmapsPasses.clear(); - for (RPI::Pass* pass : passes) - { - EsmShadowmapsPass* esmPass = static_cast(pass); - if (esmPass->GetRenderPipeline() && - AZStd::find(validPipelineIds.begin(), validPipelineIds.end(), esmPass->GetRenderPipeline()->GetId()) != validPipelineIds.end() && - esmPass->GetLightTypeName() == LightTypeName) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene()); + RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, LightTypeName](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow { - m_esmShadowmapsPasses.emplace_back(esmPass); - } - } + EsmShadowmapsPass* esmPass = static_cast(pass); + if (esmPass->GetLightTypeName() == LightTypeName) + { + m_esmShadowmapsPasses.emplace_back(esmPass); + } + return RPI::PassFilterExecutionFlow::ContinueVisitingPasses; + }); } void ProjectedShadowFeatureProcessor::UpdateFilterParameters() diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index fafcb25a08..8939f1845d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -97,8 +97,8 @@ namespace AZ::Render // Functions for caching the ProjectedShadowmapsPass and EsmShadowmapsPass. void CachePasses(); - AZStd::vector CacheProjectedShadowmapsPass(); - void CacheEsmShadowmapsPass(const AZStd::vector& validPipelineIds); + void CacheProjectedShadowmapsPass(); + void CacheEsmShadowmapsPass(); //! Functions to update the parameter of Gaussian filter used in ESM. void UpdateFilterParameters(); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index e0209702dc..4c379c4239 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -241,12 +242,12 @@ namespace AZ void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) { - InitSkinningAndMorphPass(pipeline->GetRootPass()); + InitSkinningAndMorphPass(pipeline.get()); } void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { - InitSkinningAndMorphPass(renderPipeline->GetRootPass()); + InitSkinningAndMorphPass(renderPipeline); } void SkinnedMeshFeatureProcessor::OnBeginPrepareRender() @@ -289,9 +290,10 @@ namespace AZ return false; } - void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(const RPI::Ptr pipelineRootPass) + void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline) { - RPI::Ptr skinningPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "SkinningPass" }); + RPI::PassFilter skinPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "SkinningPass" }, renderPipeline); + RPI::Ptr skinningPass = RPI::PassSystemInterface::Get()->FindFirstPass(skinPassFilter); if (skinningPass) { SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast(skinningPass.get()); @@ -310,7 +312,8 @@ namespace AZ } } - RPI::Ptr morphTargetPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "MorphTargetPass" }); + RPI::PassFilter morphPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "MorphTargetPass" }, renderPipeline); + RPI::Ptr morphTargetPass = RPI::PassSystemInterface::Get()->FindFirstPass(morphPassFilter); if (morphTargetPass) { MorphTargetComputePass* morphTargetComputePass = azdynamic_cast(morphTargetPass.get()); diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h index 2e93acf2cd..5b7ab943e1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.h @@ -66,7 +66,7 @@ namespace AZ private: AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor); - void InitSkinningAndMorphPass(const RPI::Ptr pipelineRootPass); + void InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline); SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override; bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index 36994ec03b..6523f0a6d8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -68,9 +68,6 @@ namespace AZ template Ptr FindChildPass() const; - //! Searches the tree for the first pass that has same pass name (Depth-first search). Return nullptr if none found. - Ptr FindPassByNameRecursive(const Name& passName) const; - //! Gets the list of children. Useful for validating hierarchies AZStd::array_view> GetChildren() const; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index 34eaae4495..e7b9825ecb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -139,6 +139,10 @@ namespace AZ //! Returns the number of output attachment bindings uint32_t GetOutputCount() const; + //! Returns the pass template which was used for create this pass. + //! It may return nullptr if the pass wasn't create from a template + const PassTemplate* GetPassTemplate() const; + //! Enable/disable this pass //! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered. void SetEnabled(bool enabled); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h index c31f353adb..c42991725e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassFilter.h @@ -16,95 +16,85 @@ namespace AZ { namespace RPI { - // A base class for a filter which can be used to filter passes - class PassFilter - { - public: - //! Whether the input pass matches with the filter - virtual bool Matches(const Pass* pass) const = 0; - - //! Return the pass' name if a pass name is used for the filter. - //! Return nullptr if the filter doesn't have pass name used for matching - virtual const Name* GetPassName() const = 0; + class Scene; + class RenderPipeline; - //! Return this filter's info as a string - virtual AZStd::string ToString() const = 0; - }; - - //! Filter for passes which have a matching name and also with ordered parents. - //! For example, if the filter is initialized with - //! pass name: "ShadowPass1" - //! pass parents names: "MainPipeline", "Shadow" - //! Passes with these names match the filter: - //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" - //! or "Root.MainPipeline.Shadow.ShadowPass1" - //! or "MainPipeline.Shadow.Group1.ShadowPass1" - //! - //! Passes with these names wont match: - //! "MainPipeline.ShadowPass1" - //! or "Shadow.MainPipeline.ShadowPass1" - class PassHierarchyFilter - : public PassFilter + class PassFilter { public: - AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter); - AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); - - //! Construct filter with only pass name. - PassHierarchyFilter(const Name& passName); - - virtual ~PassHierarchyFilter() = default; - - //! Construct filter with pass name and its parents' names in the order of the hierarchy - //! This means k-th element is always an ancestor of the (k-1)-th element. - //! And the last element is the pass name. - PassHierarchyFilter(const AZStd::vector& passHierarchy); - PassHierarchyFilter(const AZStd::vector& passHierarchy); - - // PassFilter overrides... - bool Matches(const Pass* pass) const override; - const Name* GetPassName() const override; - AZStd::string ToString() const override; + static PassFilter CreateWithPassName(Name passName, const Scene* scene); + static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline); + + //! Create a PassFilter with pass hierarchy information + //! Filter for passes which have a matching name and also with ordered parents. + //! For example, if the filter is initialized with + //! pass name: "ShadowPass1" + //! pass parents names: "MainPipeline", "Shadow" + //! Passes with these names match the filter: + //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" + //! or "Root.MainPipeline.Shadow.ShadowPass1" + //! or "MainPipeline.Shadow.Group1.ShadowPass1" + //! + //! Passes with these names wont match: + //! "MainPipeline.ShadowPass1" + //! or "Shadow.MainPipeline.ShadowPass1" + static PassFilter CreateWithPassHierarchy(const AZStd::vector& passHierarchy); + static PassFilter CreateWithPassHierarchy(const AZStd::vector& passHierarchy); + static PassFilter CreateWithTemplateName(Name templateName, const Scene* scene); + static PassFilter CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline); + template + static PassFilter CreateWithPassClass(); + + enum FilterOptions : uint32_t + { + Empty = 0, + PassName = AZ_BIT(0), + PassTemplateName = AZ_BIT(1), + PassClass = AZ_BIT(2), + PassHierarchy = AZ_BIT(3), + OwnerScene = AZ_BIT(4), + OwnerRenderPipeline = AZ_BIT(5) + }; + + void SetOwenrScene(const Scene* scene); + void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline); + void SetPassName(Name passName); + void SetTemplateName(Name passTemplateName); + void SetPassClass(TypeId passClassTypeId); + + const Name& GetPassName() const; + const Name& GetPassTemplateName() const; + + uint32_t GetEnabledFilterOptions() const; + + //! Return true if the input pass matches the filter + bool Matches(const Pass* pass) const; + + //! Return true if the input pass matches the filter with selected filter options + //! The input filter options should be a subset of options returned by GetEnabledFilterOptions() + //! This function is used to avoid extra checks for passes which was already filtered. + //! Check PassLibrary::ForEachPass() function's implementation for more details + bool Matches(const Pass* pass, uint32_t options) const; private: - PassHierarchyFilter() = delete; + void UpdateFilterOptions(); - AZStd::vector m_parentNames; Name m_passName; + Name m_templateName; + TypeId m_passClassTypeId = TypeId::CreateNull(); + AZStd::vector m_parentNames; + const RenderPipeline* m_ownerRenderPipeline = nullptr; + const Scene* m_ownerScene = nullptr; + uint32_t m_filterOptions = 0; }; - //! Filter for passes based on their class. - template - class PassClassFilter - : public PassFilter - { - public: - AZ_RTTI(PassClassFilter, "{AF6E3AD5-433A-462A-997A-F36D8A551D02}", PassFilter); - AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); - PassClassFilter() = default; - - // PassFilter overrides... - bool Matches(const Pass* pass) const override; - const Name* GetPassName() const override; - AZStd::string ToString() const override; - }; - - template - bool PassClassFilter::Matches(const Pass* pass) const - { - return pass->RTTI_IsTypeOf(PassClass::RTTI_Type()); - } - - template - const Name* PassClassFilter::GetPassName() const - { - return nullptr; - } - - template - AZStd::string PassClassFilter::ToString() const - { - return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName()); + template + PassFilter PassFilter::CreateWithPassClass() + { + PassFilter filter; + filter.m_passClassTypeId = PassClass::RTTI_Type(); + filter.UpdateFilterOptions(); + return filter; } } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h index 0a4b1c4399..66c3c205ab 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassLibrary.h @@ -84,8 +84,8 @@ namespace AZ bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath); bool LoadPassTemplateMappings(Data::Asset mappingAsset); - //! Returns a list of passes found in the pass name mapping using the provided pass filter - AZStd::vector FindPasses(const PassFilter& passFilter) const; + //! Visit each pass which matches the filter + void ForEachPass(const PassFilter& passFilter, AZStd::function passFunction); private: diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h index 30fa27e64b..8390b0f7e2 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystem.h @@ -92,13 +92,13 @@ namespace AZ // PassSystemInterface library related functions... bool HasPassesForTemplateName(const Name& templateName) const override; - const AZStd::vector& GetPassesForTemplateName(const Name& templateName) const override; bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) override; const AZStd::shared_ptr GetPassTemplate(const Name& name) const override; void RemovePassFromLibrary(Pass* pass) override; void RegisterPass(Pass* pass) override; void UnregisterPass(Pass* pass) override; - AZStd::vector FindPasses(const PassFilter& passFilter) const override; + void ForEachPass(const PassFilter& filter, AZStd::function passFunction) override; + Pass* FindFirstPass(const PassFilter& filter) override; private: // Returns the root of the pass tree hierarchy diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h index 0e9386f3bb..7f944df88f 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/PassSystemInterface.h @@ -75,6 +75,13 @@ namespace AZ u32 m_maxDrawItemsRenderedInAPass = 0; }; + + enum PassFilterExecutionFlow : uint8_t + { + StopVisitingPasses, + ContinueVisitingPasses, + }; + class PassSystemInterface { friend class Pass; @@ -186,9 +193,6 @@ namespace AZ //! Returns true if the pass factory contains passes created with the given template name virtual bool HasPassesForTemplateName(const Name& templateName) const = 0; - //! Get the passes created with the given template name. - virtual const AZStd::vector& GetPassesForTemplateName(const Name& templateName) const = 0; - //! Adds a PassTemplate to the library virtual bool AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) = 0; @@ -197,9 +201,16 @@ namespace AZ //! Removes all references to the given pass from the pass library virtual void RemovePassFromLibrary(Pass* pass) = 0; - - //! Find matching passes from registered passes with specified filter - virtual AZStd::vector FindPasses(const PassFilter& passFilter) const = 0; + + //! Visit the matching passes from registered passes with specified filter + //! The return value of the passFunction decides if the search continues or not + //! Note: this function will find all the passes which match the pass filter even they are for render pipelines which are not added to a scene + //! This function is fast if a pass name or a pass template name is specified. + virtual void ForEachPass(const PassFilter& filter, AZStd::function passFunction) = 0; + + //! Find the first matching pass from registered passes with specified filter + //! Note: this function SHOULD ONLY be used when you are certain you only need to handle the first pass found + virtual Pass* FindFirstPass(const PassFilter& filter) = 0; private: // These functions are only meant to be used by the Pass class diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 36c28877ea..dccf5dbc2e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -149,29 +149,6 @@ namespace AZ return index.IsValid() ? m_children[index.GetIndex()] : Ptr(nullptr); } - Ptr ParentPass::FindPassByNameRecursive(const Name& passName) const - { - for (const Ptr& child : m_children) - { - if (child->GetName() == passName) - { - return child.get(); - } - - ParentPass* asParent = child->AsParent(); - if (asParent) - { - auto pass = asParent->FindPassByNameRecursive(passName); - if (pass) - { - return pass; - } - } - } - - return nullptr; - } - const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const { if (HasDrawListTag() && GetDrawListTag() == drawListTag) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index a8d94e9a91..3c1de28d6a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -238,6 +238,11 @@ namespace AZ return m_attachmentBindings[bindingIndex]; } + const PassTemplate* Pass::GetPassTemplate() const + { + return m_template.get(); + } + void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding) { // Add the index of the binding to the input, output or input/output list based on the slot type diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp index 7bd1abc0a7..d9e458c615 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassFilter.cpp @@ -8,101 +8,264 @@ #include #include +#include namespace AZ { namespace RPI { - PassHierarchyFilter::PassHierarchyFilter(const Name& passName) + PassFilter PassFilter::CreateWithPassName(Name passName, const Scene* scene) { - m_passName = passName; + PassFilter filter; + filter.m_passName = passName; + filter.m_ownerScene = scene; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassName(Name passName, const RenderPipeline* renderPipeline) + { + PassFilter filter; + filter.m_passName = passName; + filter.m_ownerRenderPipeline = renderPipeline; + filter.UpdateFilterOptions(); + return filter; } - PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector& passHierarchy) + PassFilter PassFilter::CreateWithTemplateName(Name templateName, const Scene* scene) { + PassFilter filter; + filter.m_templateName = templateName; + filter.m_ownerScene = scene; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline) + { + PassFilter filter; + filter.m_templateName = templateName; + filter.m_ownerRenderPipeline = renderPipeline; + filter.UpdateFilterOptions(); + return filter; + } + + PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector& passHierarchy) + { + PassFilter filter; if (passHierarchy.size() == 0) { AZ_Assert(false, "passHierarchy should have at least one element"); - return; + return filter; } - m_passName = Name(passHierarchy.back()); + filter.m_passName = passHierarchy.back(); - m_parentNames.resize(passHierarchy.size() - 1); - for (uint32_t index = 0; index < m_parentNames.size(); index++) + filter.m_parentNames.resize(passHierarchy.size() - 1); + for (uint32_t index = 0; index < filter.m_parentNames.size(); index++) { - m_parentNames[index] = Name(passHierarchy[index]); + filter.m_parentNames[index] = passHierarchy[index]; } + filter.UpdateFilterOptions(); + return filter; } - PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector& passHierarchy) + PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector& passHierarchy) { + PassFilter filter; if (passHierarchy.size() == 0) { AZ_Assert(false, "passHierarchy should have at least one element"); - return; + return filter; } - m_passName = passHierarchy.back(); + filter.m_passName = Name(passHierarchy.back()); - m_parentNames.resize(passHierarchy.size() - 1); - for (uint32_t index = 0; index < m_parentNames.size(); index++) + filter.m_parentNames.resize(passHierarchy.size() - 1); + for (uint32_t index = 0; index < filter.m_parentNames.size(); index++) { - m_parentNames[index] = passHierarchy[index]; + filter.m_parentNames[index] = Name(passHierarchy[index]); } + filter.UpdateFilterOptions(); + return filter; + } + + void PassFilter::SetOwenrScene(const Scene* scene) + { + m_ownerScene = scene; + UpdateFilterOptions(); + } + + void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline) + { + m_ownerRenderPipeline = renderPipeline; + UpdateFilterOptions(); } - bool PassHierarchyFilter::Matches(const Pass* pass) const + void PassFilter::SetPassName(Name passName) { - if (pass->GetName() != m_passName) + m_passName = passName; + UpdateFilterOptions(); + } + + void PassFilter::SetTemplateName(Name passTemplateName) + { + m_templateName = passTemplateName; + UpdateFilterOptions(); + } + + void PassFilter::SetPassClass(TypeId passClassTypeId) + { + m_passClassTypeId = passClassTypeId; + UpdateFilterOptions(); + } + + const Name& PassFilter::GetPassName() const + { + return m_passName; + } + + const Name& PassFilter::GetPassTemplateName() const + { + return m_templateName; + } + + uint32_t PassFilter::GetEnabledFilterOptions() const + { + return m_filterOptions; + } + + bool PassFilter::Matches(const Pass* pass) const + { + return Matches(pass, m_filterOptions); + } + + bool PassFilter::Matches(const Pass* pass, uint32_t options) const + { + AZ_Assert( (options&m_filterOptions) == options, "options should be a subset of m_filterOptions"); + + // return false if the pass doesn't have a pass template or the template's name is not matching + if (options & FilterOptions::PassTemplateName && (!pass->GetPassTemplate() || pass->GetPassTemplate()->m_name != m_templateName)) { return false; } - ParentPass* parent = pass->GetParent(); + if ((options & FilterOptions::PassName) && pass->GetName() != m_passName) + { + return false; + } - // search from the back of the array with the most close parent - for (int32_t index = static_cast(m_parentNames.size() - 1); index >= 0; index--) + if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId) { - const Name& parentName = m_parentNames[index]; - while (parent) + return false; + } + + if ((options & FilterOptions::OwnerRenderPipeline) && m_ownerRenderPipeline != pass->GetRenderPipeline()) + { + return false; + } + + // If the owner render pipeline was checked, the owner scene check can be skipped + if (options & FilterOptions::OwnerScene) + { + if (pass->GetRenderPipeline()) { - if (parent->GetName() == parentName) + // return false if the owner scene doesn't match + if (m_ownerScene != pass->GetRenderPipeline()->GetScene()) { - break; + return false; } - parent = parent->GetParent(); } - - // if parent is nullptr the it didn't find a parent has matching current parentName - if (!parent) + else { + // return false if the pass doesn't have an owner scene return false; } + } + + if ((options & FilterOptions::PassHierarchy)) + { + // Filter for passes which have a matching name and also with ordered parents. + // For example, if the filter is initialized with + // pass name: "ShadowPass1" + // pass parents names: "MainPipeline", "Shadow" + // Passes with these names match the filter: + // "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1" + // or "Root.MainPipeline.Shadow.ShadowPass1" + // or "MainPipeline.Shadow.Group1.ShadowPass1" + // + // Passes with these names wont match: + // "MainPipeline.ShadowPass1" + // or "Shadow.MainPipeline.ShadowPass1" - // move to next parent - parent = parent->GetParent(); + ParentPass* parent = pass->GetParent(); + + // search from the back of the array with the most close parent + for (int32_t index = static_cast(m_parentNames.size() - 1); index >= 0; index--) + { + const Name& parentName = m_parentNames[index]; + while (parent) + { + if (parent->GetName() == parentName) + { + break; + } + parent = parent->GetParent(); + } + + // if parent is nullptr the it didn't find a parent has matching current parentName + if (!parent) + { + return false; + } + + // move to next parent + parent = parent->GetParent(); + } } return true; } - const Name* PassHierarchyFilter::GetPassName() const + void PassFilter::UpdateFilterOptions() { - return &m_passName; - } - - AZStd::string PassHierarchyFilter::ToString() const - { - AZStd::string result = "PassHierarchyFilter"; - for (uint32_t index = 0; index < m_parentNames.size(); index++) + m_filterOptions = FilterOptions::Empty; + if (!m_passName.IsEmpty()) { - result += AZStd::string::format(" [%s]", m_parentNames[index].GetCStr()); + m_filterOptions |= FilterOptions::PassName; + } + if (!m_templateName.IsEmpty()) + { + m_filterOptions |= FilterOptions::PassTemplateName; + } + if (m_parentNames.size() > 0) + { + m_filterOptions |= FilterOptions::PassHierarchy; + } + if (m_ownerRenderPipeline) + { + m_filterOptions |= FilterOptions::OwnerRenderPipeline; + } + if (m_ownerScene) + { + // If the OwnerRenderPipeline exists, we shouldn't need to filter owner scene + // Validate the owner render pipeline belongs to the owner scene + if (m_filterOptions & FilterOptions::OwnerRenderPipeline) + { + if (m_ownerRenderPipeline->GetScene() != m_ownerScene) + { + AZ_Warning("RPI", false, "The owner scene filter doesn't match owner render pipeline. It will be skipped."); + } + } + else + { + m_filterOptions |= FilterOptions::OwnerScene; + } + } + if (!m_passClassTypeId.IsNull()) + { + m_filterOptions |= FilterOptions::PassClass; } - - result += AZStd::string::format(" [%s]", m_passName.GetCStr()); - return result; } - } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp index c43edafd6b..6a6f5f3ff9 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassLibrary.cpp @@ -85,47 +85,80 @@ namespace AZ return (GetPassesForTemplate(templateName).size() > 0); } - AZStd::vector PassLibrary::FindPasses(const PassFilter& passFilter) const + void PassLibrary::ForEachPass(const PassFilter& passFilter, AZStd::function passFunction) { - const Name* passName = passFilter.GetPassName(); + uint32_t filterOptions = passFilter.GetEnabledFilterOptions(); - AZStd::vector result; - - if (passName) + // A lambda function which visits each pass in a pass list, if the pass matches the pass filter, then call the pass function + auto visitList = [passFilter, passFunction](const AZStd::vector& passList, uint32_t options) -> PassFilterExecutionFlow { - // If the pass' name is known, find passes with matching names first - const auto constItr = m_passNameMapping.find(*passName); - if (constItr == m_passNameMapping.end()) + if (passList.size() == 0) { - return result; + return PassFilterExecutionFlow::ContinueVisitingPasses; } - - const AZStd::vector& passes = constItr->second; - - for (Pass* pass : passes) + // if there is not other filter options enabled, skip the filter and call pass functions directly + if (options == PassFilter::FilterOptions::Empty) { - if (passFilter.Matches(pass)) + for (Pass* pass : passList) { - result.push_back(pass); + // If user want to skip processing, return directly. + if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses) + { + return PassFilterExecutionFlow::StopVisitingPasses; + } } + return PassFilterExecutionFlow::ContinueVisitingPasses; } - } - else - { - // If the filter doesn't know matching pass' name, need to go through all registered passes - for (auto& namePasses : m_passNameMapping) + + // Check with the pass filter and call pass functions + for (Pass* pass : passList) { - for (Pass* pass : namePasses.second) + if (passFilter.Matches(pass, options)) { - if (passFilter.Matches(pass)) + if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses) { - result.push_back(pass); + return PassFilterExecutionFlow::StopVisitingPasses; } } } + return PassFilterExecutionFlow::ContinueVisitingPasses; + }; + + // Check pass template name first + if (filterOptions & PassFilter::FilterOptions::PassTemplateName) + { + auto entry = GetEntry(passFilter.GetPassTemplateName()); + if (!entry) + { + return; + } + + filterOptions &= ~(PassFilter::FilterOptions::PassTemplateName); + visitList(entry->m_passes, filterOptions); + return; + } + else if (filterOptions & PassFilter::FilterOptions::PassName) + { + const auto constItr = m_passNameMapping.find(passFilter.GetPassName()); + if (constItr == m_passNameMapping.end()) + { + return; + } + + filterOptions &= ~(PassFilter::FilterOptions::PassName); + visitList(constItr->second, filterOptions); + return; } - return result; + // check againest every passes. This might be slow + AZ_PROFILE_SCOPE(RPI, "PassLibrary::ForEachPass"); + for (auto& namePasses : m_passNameMapping) + { + if (visitList(namePasses.second, filterOptions) == PassFilterExecutionFlow::StopVisitingPasses) + { + return; + } + } } // Add Functions... @@ -419,3 +452,4 @@ namespace AZ } // namespace RPI } // namespace AZ + diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp index f4f51f97b7..7f2948c13a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/PassSystem.cpp @@ -456,11 +456,6 @@ namespace AZ return m_passLibrary.HasPassesForTemplate(templateName); } - const AZStd::vector& PassSystem::GetPassesForTemplateName(const Name& templateName) const - { - return m_passLibrary.GetPassesForTemplate(templateName); - } - bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr& passTemplate) { return m_passLibrary.AddPassTemplate(name, passTemplate); @@ -487,10 +482,21 @@ namespace AZ RemovePassFromLibrary(pass); --m_passCounter; } + + void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function passFunction) + { + return m_passLibrary.ForEachPass(filter, passFunction); + } - AZStd::vector PassSystem::FindPasses(const PassFilter& passFilter) const + Pass* PassSystem::FindFirstPass(const PassFilter& filter) { - return m_passLibrary.FindPasses(passFilter); + Pass* foundPass = nullptr; + m_passLibrary.ForEachPass(filter, [&foundPass](RPI::Pass* pass) ->PassFilterExecutionFlow + { + foundPass = pass; + return PassFilterExecutionFlow::StopVisitingPasses; + }); + return foundPass; } SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const diff --git a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp index 420ab1798a..690f212ec7 100644 --- a/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Pass/PassTests.cpp @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -573,7 +575,7 @@ namespace UnitTest EXPECT_TRUE(pass != nullptr); } - TEST_F(PassTests, PassHierarchyFilter) + TEST_F(PassTests, PassFilter_PassHierarchy) { m_data->AddPassTemplatesToLibrary(); @@ -587,62 +589,55 @@ namespace UnitTest parent2->AsParent()->AddChild(parent1); parent1->AsParent()->AddChild(pass); - { - // Filter with only pass name - PassHierarchyFilter filter(Name("pass1")); - EXPECT_TRUE(filter.Matches(pass.get())); - } - { // Filter with pass hierarchy which has only one element - PassHierarchyFilter filter({ Name("pass1") }); + PassFilter filter = PassFilter::CreateWithPassHierarchy({Name("pass1")}); EXPECT_TRUE(filter.Matches(pass.get())); } { - // Filter with empty pass hierarchy. Result one assert + // Filter with empty pass hierarchy, triggers one assert AZ_TEST_START_TRACE_SUPPRESSION; - PassHierarchyFilter filter(AZStd::vector{}); + PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector{}); AZ_TEST_STOP_TRACE_SUPPRESSION(1); - EXPECT_FALSE(filter.Matches(pass.get())); } { // Filters with partial hierarchy by using string vector AZStd::vector passHierarchy1 = { "parent1", "pass1" }; - PassHierarchyFilter filter1(passHierarchy1); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1); EXPECT_TRUE(filter1.Matches(pass.get())); AZStd::vector passHierarchy2 = { "parent2", "pass1" }; - PassHierarchyFilter filter2(passHierarchy2); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2); EXPECT_TRUE(filter2.Matches(pass.get())); AZStd::vector passHierarchy3 = { "parent3", "parent2", "pass1" }; - PassHierarchyFilter filter3(passHierarchy3); + PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3); EXPECT_TRUE(filter3.Matches(pass.get())); } { // Filters with partial hierarchy by using Name vector AZStd::vector passHierarchy1 = { Name("parent1"), Name("pass1") }; - PassHierarchyFilter filter1(passHierarchy1); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1); EXPECT_TRUE(filter1.Matches(pass.get())); AZStd::vector passHierarchy2 = { Name("parent2"), Name("pass1")}; - PassHierarchyFilter filter2(passHierarchy2); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2); EXPECT_TRUE(filter2.Matches(pass.get())); AZStd::vector passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") }; - PassHierarchyFilter filter3(passHierarchy3); + PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3); EXPECT_TRUE(filter3.Matches(pass.get())); } { // Find non-leaf pass - PassHierarchyFilter filter1(AZStd::vector{"parent3", "parent1"}); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"parent3", "parent1"}); EXPECT_TRUE(filter1.Matches(parent1.get())); - - PassHierarchyFilter filter2(Name("parent1")); + + PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") }); EXPECT_TRUE(filter2.Matches(parent1.get())); EXPECT_FALSE(filter2.Matches(pass.get())); } @@ -650,11 +645,131 @@ namespace UnitTest { // Failed to find pass // Mis-matching hierarchy - PassHierarchyFilter filter1(AZStd::vector{"Parent1", "Parent3", "pass1"}); + PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"Parent1", "Parent3", "pass1"}); EXPECT_FALSE(filter1.Matches(pass.get())); // Mis-matching name - PassHierarchyFilter filter2(AZStd::vector{"Parent1", "pass1"}); + PassFilter filter2 = PassFilter::CreateWithPassHierarchy(AZStd::vector{"Parent1", "pass1"}); EXPECT_FALSE(filter2.Matches(parent1.get())); } } + + TEST_F(PassTests, PassFilter_Empty_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + Ptr parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2")); + Ptr parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3")); + + parent3->AsParent()->AddChild(parent2); + parent2->AsParent()->AddChild(parent1); + parent1->AsParent()->AddChild(pass); + + PassFilter filter; + + // Any pass can match an empty filter + EXPECT_TRUE(filter.Matches(pass.get())); + EXPECT_TRUE(filter.Matches(parent1.get())); + EXPECT_TRUE(filter.Matches(parent2.get())); + EXPECT_TRUE(filter.Matches(parent3.get())); + } + + TEST_F(PassTests, PassFilter_PassClass_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr depthPass = m_passSystem->CreatePassFromTemplate(Name("DepthPrePass"), Name("depthPass")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + + parent1->AsParent()->AddChild(pass); + parent1->AsParent()->AddChild(depthPass); + + PassFilter filter1 = PassFilter::CreateWithPassClass(); + + EXPECT_TRUE(filter1.Matches(pass.get())); + EXPECT_FALSE(filter1.Matches(parent1.get())); + + PassFilter filter2 = PassFilter::CreateWithPassClass(); + EXPECT_FALSE(filter2.Matches(pass.get())); + EXPECT_TRUE(filter2.Matches(parent1.get())); + } + + TEST_F(PassTests, PassFilter_PassTemplate_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr childPass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + + PassFilter filter1 = PassFilter::CreateWithTemplateName(Name("Pass"), (Scene*) nullptr); + // childPass doesn't have a template + EXPECT_FALSE(filter1.Matches(childPass.get())); + + PassFilter filter2 = PassFilter::CreateWithTemplateName(Name("ParentPass"), (Scene*) nullptr); + EXPECT_TRUE(filter2.Matches(parent1.get())); + } + + TEST_F(PassTests, ForEachPass_PassTemplateFilter_Success) + { + m_data->AddPassTemplatesToLibrary(); + + // create a pass tree + Ptr pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1")); + Ptr parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1")); + Ptr parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2")); + Ptr parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3")); + + parent3->AsParent()->AddChild(parent2); + parent2->AsParent()->AddChild(parent1); + parent1->AsParent()->AddChild(pass); + + // Create render pipeline + const RPI::PipelineViewTag viewTag{ "viewTag1" }; + RPI::RenderPipelineDescriptor desc; + desc.m_mainViewTagName = viewTag.GetStringView(); + desc.m_name = "TestPipeline"; + RPI::RenderPipelinePtr pipeline = RPI::RenderPipeline::CreateRenderPipeline(desc); + Ptr parent4 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent4")); + pipeline->GetRootPass()->AddChild(parent4); + + Name templateName = Name("ParentPass"); + PassFilter filter1 = PassFilter::CreateWithTemplateName(templateName, (RenderPipeline*)nullptr); + + int count = 0; + m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow + { + EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName); + count++; + return PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + // three from CreatePassFromTemplate() calls and one from Render Pipeline. + EXPECT_TRUE(count == 4); + + count = 0; + m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow + { + EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName); + count++; + return PassFilterExecutionFlow::StopVisitingPasses; + }); + EXPECT_TRUE(count == 1); + + PassFilter filter2 = PassFilter::CreateWithTemplateName(templateName, pipeline.get()); + count = 0; + m_passSystem->ForEachPass(filter2, [&count]([[maybe_unused]] RPI::Pass* pass) -> PassFilterExecutionFlow + { + count++; + return PassFilterExecutionFlow::ContinueVisitingPasses; + }); + + // only the ParentPass in the render pipeline was found + EXPECT_TRUE(count == 1); + + } } diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index a0be18f0e2..161160e16f 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -142,12 +143,13 @@ namespace AZ EnablePasses(true); } - void HairFeatureProcessor::EnablePasses([[maybe_unused]] bool enable) + void HairFeatureProcessor::EnablePasses(bool enable) { - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName); - if (desiredPass) + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); + if (pass) { - desiredPass->SetEnabled(enable); + pass->SetEnabled(enable); } } @@ -309,10 +311,17 @@ namespace AZ m_forceClearRenderData = true; } + bool HairFeatureProcessor::HasHairParentPass() + { + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); + return pass; + } + void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline.get()->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -323,10 +332,10 @@ namespace AZ m_forceRebuildRenderData = true; } - void HairFeatureProcessor::OnRenderPipelineRemoved(RPI::RenderPipeline* renderPipeline) + void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -338,7 +347,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) + if (!HasHairParentPass()) { return; } @@ -457,7 +466,8 @@ namespace AZ { m_computePasses[passName] = nullptr; - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(passName); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(passName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_computePasses[passName] = static_cast(desiredPass.get()); @@ -478,8 +488,9 @@ namespace AZ bool HairFeatureProcessor::InitPPLLFillPass() { m_hairPPLLRasterPass = nullptr; // reset it to null, just in case it fails to load the assets properly - - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLRasterPassName); + + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLRasterPassName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_hairPPLLRasterPass = static_cast(desiredPass.get()); @@ -497,7 +508,8 @@ namespace AZ { m_hairPPLLResolvePass = nullptr; // reset it to null, just in case it fails to load the assets properly - RPI::Ptr desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLResolvePassName); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLResolvePassName, m_renderPipeline); + RPI::Ptr desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); if (desiredPass) { m_hairPPLLResolvePass = static_cast(desiredPass.get()); @@ -518,8 +530,8 @@ namespace AZ m_hairShortCutGeometryDepthAlphaPass = nullptr; m_hairShortCutGeometryShadingPass = nullptr; - m_hairShortCutGeometryDepthAlphaPass = static_cast( - m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryDepthAlphaPassName).get()); + RPI::PassFilter depthAlphaPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryDepthAlphaPassName, m_renderPipeline); + m_hairShortCutGeometryDepthAlphaPass = static_cast(RPI::PassSystemInterface::Get()->FindFirstPass(depthAlphaPassFilter)); if (m_hairShortCutGeometryDepthAlphaPass) { m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this); @@ -530,8 +542,8 @@ namespace AZ return false; } - m_hairShortCutGeometryShadingPass = static_cast( - m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryShadingPassName).get()); + RPI::PassFilter shaderingPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryShadingPassName, m_renderPipeline); + m_hairShortCutGeometryShadingPass = static_cast(RPI::PassSystemInterface::Get()->FindFirstPass(shaderingPassFilter)); if (m_hairShortCutGeometryShadingPass) { m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this); diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h index 46660a6623..f810967824 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h @@ -165,6 +165,8 @@ namespace AZ void EnablePasses(bool enable); + bool HasHairParentPass(); + //! The following will serve to register the FP in the Thumbnail system AZStd::vector m_hairFeatureProcessorRegistryName; From 5e09f8580164b83524a66ce1e6f8965abd5efa10 Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Mon, 25 Oct 2021 11:08:49 -0700 Subject: [PATCH 054/200] Fixed some files missed when groundplane_521 was renamed to 512 (#4958) * Fixed references to 521x521 to reference the correct 512x512 FBX file Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Fixed asset hints Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Signed-off-by: Gene Walters --- Assets/Editor/Prefabs/Default_Level.prefab | 4 ++-- .../Prefabs/test_sponza_material_conversion.prefab | 10 +++++----- .../CommonFeatures/Assets/LevelAssets/default.slice | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Assets/Editor/Prefabs/Default_Level.prefab b/Assets/Editor/Prefabs/Default_Level.prefab index d02d669f53..0267131fa0 100644 --- a/Assets/Editor/Prefabs/Default_Level.prefab +++ b/Assets/Editor/Prefabs/Default_Level.prefab @@ -185,7 +185,7 @@ { "id": { "materialAssetId": { - "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}", + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", "subId": 803645540 } } @@ -197,7 +197,7 @@ "id": { "lodIndex": 0, "materialAssetId": { - "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}", + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", "subId": 803645540 } } diff --git a/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab b/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab index b5aed9d14b..92874574e4 100644 --- a/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab +++ b/Gems/AtomContent/Sponza/Assets/Prefabs/test_sponza_material_conversion.prefab @@ -581,7 +581,7 @@ { "id": { "materialAssetId": { - "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}", + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", "subId": 803645540 } } @@ -593,7 +593,7 @@ "id": { "lodIndex": 0, "materialAssetId": { - "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}", + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", "subId": 803645540 } } @@ -608,10 +608,10 @@ "Configuration": { "ModelAsset": { "assetId": { - "guid": "{935F694A-8639-515B-8133-81CDC7948E5B}", - "subId": 277333723 + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", + "subId": 277889906 }, - "assetHint": "objects/groudplane/groundplane_521x521m.azmodel" + "assetHint": "objects/groudplane/groundplane_512x512m.azmodel" } } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice b/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice index b4c9eac10f..e0c7c9e456 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice +++ b/Gems/AtomLyIntegration/CommonFeatures/Assets/LevelAssets/default.slice @@ -836,7 +836,7 @@ - + From e00c760ffd42a373358ae0243bfc7f8efd50041e Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Mon, 25 Oct 2021 13:23:43 -0500 Subject: [PATCH 055/200] Normalize Shader vs Shaders Folders (#4925) Normalize Shader vs Shaders Folders (#4925) Signed-off-by: garrieta Signed-off-by: Gene Walters --- .../RPI/Assets/{Shader => Shaders}/DecomposeMsImage.azsl | 0 .../Assets/{Shader => Shaders}/DecomposeMsImage.shader | 0 .../Atom/RPI/Assets/{Shader => Shaders}/ImagePreview.azsl | 0 .../RPI/Assets/{Shader => Shaders}/ImagePreview.shader | 0 .../{Shader => Shaders}/ImagePreview.shadervariantlist | 0 .../RPI/Assets/{Shader => Shaders}/SceneAndViewSrgs.azsl | 0 .../Assets/{Shader => Shaders}/SceneAndViewSrgs.shader | 0 Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake | 8 ++++---- .../Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h | 2 +- .../Code/Source/RPI.Public/Pass/AttachmentReadback.cpp | 2 +- .../Pass/Specific/ImageAttachmentPreviewPass.cpp | 2 +- Gems/Atom/RPI/Registry/atom_rpi.setreg | 2 +- 12 files changed, 8 insertions(+), 8 deletions(-) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/DecomposeMsImage.azsl (100%) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/DecomposeMsImage.shader (100%) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/ImagePreview.azsl (100%) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/ImagePreview.shader (100%) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/ImagePreview.shadervariantlist (100%) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/SceneAndViewSrgs.azsl (100%) rename Gems/Atom/RPI/Assets/{Shader => Shaders}/SceneAndViewSrgs.shader (100%) diff --git a/Gems/Atom/RPI/Assets/Shader/DecomposeMsImage.azsl b/Gems/Atom/RPI/Assets/Shaders/DecomposeMsImage.azsl similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/DecomposeMsImage.azsl rename to Gems/Atom/RPI/Assets/Shaders/DecomposeMsImage.azsl diff --git a/Gems/Atom/RPI/Assets/Shader/DecomposeMsImage.shader b/Gems/Atom/RPI/Assets/Shaders/DecomposeMsImage.shader similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/DecomposeMsImage.shader rename to Gems/Atom/RPI/Assets/Shaders/DecomposeMsImage.shader diff --git a/Gems/Atom/RPI/Assets/Shader/ImagePreview.azsl b/Gems/Atom/RPI/Assets/Shaders/ImagePreview.azsl similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/ImagePreview.azsl rename to Gems/Atom/RPI/Assets/Shaders/ImagePreview.azsl diff --git a/Gems/Atom/RPI/Assets/Shader/ImagePreview.shader b/Gems/Atom/RPI/Assets/Shaders/ImagePreview.shader similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/ImagePreview.shader rename to Gems/Atom/RPI/Assets/Shaders/ImagePreview.shader diff --git a/Gems/Atom/RPI/Assets/Shader/ImagePreview.shadervariantlist b/Gems/Atom/RPI/Assets/Shaders/ImagePreview.shadervariantlist similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/ImagePreview.shadervariantlist rename to Gems/Atom/RPI/Assets/Shaders/ImagePreview.shadervariantlist diff --git a/Gems/Atom/RPI/Assets/Shader/SceneAndViewSrgs.azsl b/Gems/Atom/RPI/Assets/Shaders/SceneAndViewSrgs.azsl similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/SceneAndViewSrgs.azsl rename to Gems/Atom/RPI/Assets/Shaders/SceneAndViewSrgs.azsl diff --git a/Gems/Atom/RPI/Assets/Shader/SceneAndViewSrgs.shader b/Gems/Atom/RPI/Assets/Shaders/SceneAndViewSrgs.shader similarity index 100% rename from Gems/Atom/RPI/Assets/Shader/SceneAndViewSrgs.shader rename to Gems/Atom/RPI/Assets/Shaders/SceneAndViewSrgs.shader diff --git a/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake b/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake index 9e89427a70..40478da961 100644 --- a/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake +++ b/Gems/Atom/RPI/Assets/atom_rpi_asset_files.cmake @@ -7,10 +7,10 @@ # set(FILES - Shader/DecomposeMsImage.azsl - Shader/DecomposeMsImage.shader - Shader/ImagePreview.azsl - Shader/ImagePreview.shader + Shaders/DecomposeMsImage.azsl + Shaders/DecomposeMsImage.shader + Shaders/ImagePreview.azsl + Shaders/ImagePreview.shader ShaderLib/Atom/RPI/Math.azsli ShaderLib/Atom/RPI/TangentSpace.azsli ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h index 1b7b32c1e9..7f57b30326 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/RPISystemDescriptor.h @@ -32,7 +32,7 @@ namespace AZ //! The asset cache relative path of the only common shader asset for the RPI system that is used //! as means to load the layout for scene srg and view srg. This is used to create any RPI::Scene. - AZStd::string m_commonSrgsShaderAssetPath = "shader/sceneandviewsrgs.azshader"; + AZStd::string m_commonSrgsShaderAssetPath = "shaders/sceneandviewsrgs.azshader"; ImageSystemDescriptor m_imageSystemDescriptor; GpuQuerySystemDescriptor m_gpuQuerySystemDescriptor; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp index c19ae565d0..890e87a7a5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/AttachmentReadback.cpp @@ -121,7 +121,7 @@ namespace AZ m_fence->Init(*device, RHI::FenceState::Reset); // Load shader and srg - const char* ShaderPath = "shader/decomposemsimage.azshader"; + const char* ShaderPath = "shaders/decomposemsimage.azshader"; m_decomposeShader = LoadCriticalShader(ShaderPath); if (m_decomposeShader == nullptr) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp index 105936f64d..74d52fd64d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.cpp @@ -244,7 +244,7 @@ namespace AZ m_needsShaderLoad = false; // Load Shader - const char* ShaderPath = "shader/imagepreview.azshader"; + const char* ShaderPath = "shaders/imagepreview.azshader"; Data::Asset shaderAsset = RPI::FindShaderAsset(ShaderPath); m_shader = Shader::FindOrCreate(shaderAsset); if (m_shader == nullptr) diff --git a/Gems/Atom/RPI/Registry/atom_rpi.setreg b/Gems/Atom/RPI/Registry/atom_rpi.setreg index bcbade5d38..16ce8b3bd7 100644 --- a/Gems/Atom/RPI/Registry/atom_rpi.setreg +++ b/Gems/Atom/RPI/Registry/atom_rpi.setreg @@ -3,7 +3,7 @@ "Atom": { "RPI": { "Initialization": { - "CommonSrgsShaderAssetPath": "shader/sceneandviewsrgs.azshader", + "CommonSrgsShaderAssetPath": "shaders/sceneandviewsrgs.azshader", "ImageSystemDescriptor": { "AssetStreamingImagePoolSize": 2147483648, // 2 * 1024 * 1024 * 1024 "SystemStreamingImagePoolSize": 134217728, // 128 * 1024 * 1024 From 7f6d72b5d9388eeaec3c985e118136fe0059f626 Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Mon, 25 Oct 2021 13:26:53 -0500 Subject: [PATCH 056/200] Added Hydra API to extract all the classes, globals and EBuses exposed (#4953) * Added Hydra API to extract all the classes, globals and EBuses exposed to lua: azlmbr.script.LuaSymbolsReporterBus: GetListOfClasses GetListOfGlobalProperties GetListOfGlobalFunctions GetListOfEBuses Also exposed to Hydra the classes that can be used to dump the symbols azlmbr.script.LuaPropertySymbol azlmbr.script.LuaMethodSymbol azlmbr.script.LuaClassSymbol azlmbr.script.LuaEBusSender azlmbr.script.LuaEBusSymbol The python file Assets/Editor/Scripts/lua_symbols.py can be used with "pyRunFile [output.txt]" to create Game/output.txt will all the symbols OR passing up to three additional arguments "c" or "g" or "e" to dump only classes, globals or ebuses or a combination of those. Example: To create an output file with only classes and Ebuses: "pyRunFile [output.txt] c e" Signed-off-by: garrieta Signed-off-by: Gene Walters --- Assets/Editor/Scripts/lua_symbols.py | 116 +++++ .../Application/ToolsApplication.cpp | 4 +- .../AzToolsFrameworkModule.cpp | 2 + .../Script/LuaSymbolsReporterBus.h | 110 ++++ .../LuaSymbolsReporterSystemComponent.cpp | 475 ++++++++++++++++++ .../LuaSymbolsReporterSystemComponent.h | 73 +++ .../aztoolsframework_files.cmake | 3 + 7 files changed, 782 insertions(+), 1 deletion(-) create mode 100644 Assets/Editor/Scripts/lua_symbols.py create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterBus.h create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h diff --git a/Assets/Editor/Scripts/lua_symbols.py b/Assets/Editor/Scripts/lua_symbols.py new file mode 100644 index 0000000000..b21edb41d0 --- /dev/null +++ b/Assets/Editor/Scripts/lua_symbols.py @@ -0,0 +1,116 @@ +# +# 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 script shows basic usage of LuaSymbolsReporterBus, +# Which can be used to report all symbols available for +# game scripting with Lua. + +import sys +import os + +import azlmbr.bus as azbus +import azlmbr.script as azscript +import azlmbr.legacy.general as azgeneral + + +def _dump_class_symbol(class_symbol: azlmbr.script.LuaClassSymbol): + print(f"** {class_symbol}") + print("Properties:") + for property_symbol in class_symbol.properties: + print(f" - {property_symbol}") + print("Methods:") + for method_symbol in class_symbol.methods: + print(f" - {method_symbol}") + + +def _dump_lua_classes(): + class_symbols = azscript.LuaSymbolsReporterBus(azbus.Broadcast, + "GetListOfClasses") + print("======== Classes ==========") + sorted_classes_by_named = sorted(class_symbols, key=lambda class_symbol: class_symbol.name) + for class_symbol in sorted_classes_by_named: + _dump_class_symbol(class_symbol) + print("\n\n") + + +def _dump_lua_globals(): + global_properties = azscript.LuaSymbolsReporterBus(azbus.Broadcast, + "GetListOfGlobalProperties") + print("======== Global Properties ==========") + sorted_properties_by_name = sorted(global_properties, key=lambda symbol: symbol.name) + for property_symbol in sorted_properties_by_name: + print(f"- {property_symbol}") + print("\n\n") + global_functions = azscript.LuaSymbolsReporterBus(azbus.Broadcast, + "GetListOfGlobalFunctions") + print("======== Global Functions ==========") + sorted_functions_by_name = sorted(global_functions, key=lambda symbol: symbol.name) + for function_symbol in sorted_functions_by_name: + print(f"- {function_symbol}") + print("\n\n") + + +def _dump_lua_ebus(ebus_symbol: azlmbr.script.LuaEBusSymbol): + print(f">> {ebus_symbol}") + sorted_senders = sorted(ebus_symbol.senders, key=lambda symbol: symbol.name) + for sender in sorted_senders: + print(f" - {sender}") + print("\n") + + +def _dump_lua_ebuses(): + ebuses = azscript.LuaSymbolsReporterBus(azbus.Broadcast, + "GetListOfEBuses") + print("======== Ebus List ==========") + sorted_ebuses_by_name = sorted(ebuses, key=lambda symbol: symbol.name) + for ebus_symbol in sorted_ebuses_by_name: + _dump_lua_ebus(ebus_symbol) + print("\n\n") + + +class WhatToDo: + DumpClasses = "c" + DumpGlobals = "g" + DumpEBuses = "e" + +if __name__ == "__main__": + redirecting_stdout = False + orig_stdout = sys.stdout + if len(sys.argv) > 1: + output_file_name = sys.argv[1] + if not os.path.isabs(output_file_name): + game_root_path = os.path.normpath(azgeneral.get_game_folder()) + output_file_name = os.path.join(game_root_path, output_file_name) + try: + file_obj = open(output_file_name, 'wt') + sys.stdout = file_obj + redirecting_stdout = True + except Exception as e: + print(f"Failed to open {output_file_name}: {e}") + sys.exit(-1) + + what_to_do = [action.lower() for action in sys.argv[2:]] + + # If the user did not specify what to do, then let's dump + # all the symbols. + if len(what_to_do) < 1: + what_to_do = [WhatToDo.DumpClasses, WhatToDo.DumpGlobals, WhatToDo.DumpEBuses] + + for action in what_to_do: + if action == WhatToDo.DumpClasses: + _dump_lua_classes() + elif action == WhatToDo.DumpGlobals: + _dump_lua_globals() + elif action == WhatToDo.DumpEBuses: + _dump_lua_ebuses() + + if redirecting_stdout: + sys.stdout.close() + sys.stdout = orig_stdout + print(f" Lua Symbols Are available in: {output_file_name}") diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index fbd066ec6e..3f254581dd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -70,6 +70,7 @@ #include #include #include +#include #include AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QFileInfo::d_ptr': class 'QSharedDataPointer' needs to have dll-interface to be used by clients of class 'QFileInfo' @@ -273,7 +274,8 @@ namespace AzToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), - azrtti_typeid() + azrtti_typeid(), + azrtti_typeid(), }); return components; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp index d2a88df544..2cdf409125 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AzToolsFrameworkModule.cpp @@ -54,6 +54,7 @@ #include #include #include +#include AZ_DEFINE_BUDGET(AzToolsFramework); @@ -106,6 +107,7 @@ namespace AzToolsFramework AzToolsFramework::Components::EditorIntersectorComponent::CreateDescriptor(), AzToolsFramework::AzToolsFrameworkConfigurationSystemComponent::CreateDescriptor(), AzToolsFramework::Components::EditorEntityUiSystemComponent::CreateDescriptor(), + AzToolsFramework::Script::LuaSymbolsReporterSystemComponent::CreateDescriptor(), }); } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterBus.h new file mode 100644 index 0000000000..f0bfecef38 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterBus.h @@ -0,0 +1,110 @@ +/* + * 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 + +#include +#include + +namespace AzToolsFramework +{ + namespace Script + { + struct LuaPropertySymbol + { + AZ_TYPE_INFO(LuaPropertySymbol, "{5AFB147F-50A4-4F00-9F82-D8D5BBC970D6}"); + static void Reflect(AZ::ReflectContext* context); + + AZStd::string m_name; + bool m_canRead; + bool m_canWrite; + + AZStd::string ToString() const; + }; + + struct LuaMethodSymbol + { + AZ_TYPE_INFO(LuaMethodSymbol, "{7B074A36-C81D-46A0-8D2F-62E426EBE38A}"); + static void Reflect(AZ::ReflectContext* context); + + AZStd::string m_name; + AZStd::string m_debugArgumentInfo; + + AZStd::string ToString() const; + }; + + struct LuaClassSymbol + { + AZ_TYPE_INFO(LuaClassSymbol, "{5FBE5841-A8E1-44B6-BEDA-22302CF8DF5F}"); + static void Reflect(AZ::ReflectContext* context); + + AZStd::string m_name; + AZ::Uuid m_typeId; + AZStd::vector m_properties; + AZStd::vector m_methods; + + AZStd::string ToString() const; + }; + + struct LuaEBusSender + { + AZ_TYPE_INFO(LuaEBusSender, "{23EE4188-0924-49DB-BF3F-EB7AAB6D5E5C}"); + static void Reflect(AZ::ReflectContext* context); + + AZStd::string m_name; + AZStd::string m_debugArgumentInfo; + AZStd::string m_category; + + AZStd::string ToString() const; + }; + + struct LuaEBusSymbol + { + AZ_TYPE_INFO(LuaEBusSymbol, "{381C5639-A916-4D2E-B825-50A3F2D93137}"); + static void Reflect(AZ::ReflectContext* context); + + AZStd::string m_name; + bool m_canBroadcast; + bool m_canQueue; + bool m_hasHandler; + + AZStd::vector m_senders; + + AZStd::string ToString() const; + }; + + // This is an EBus useful to scrape classes, globals and EBuses exposed to game scripting + // e.g: Lua. + class LuaSymbolsReporterRequests + { + public: + AZ_RTTI(LuaSymbolsReporterRequests, "{3FF9A105-3159-49FF-8DC6-4948AE7B4AB8}"); + virtual ~LuaSymbolsReporterRequests() = default; + // Put your public methods here + + virtual const AZStd::vector& GetListOfClasses() = 0; + virtual const AZStd::vector& GetListOfGlobalProperties() = 0; + virtual const AZStd::vector& GetListOfGlobalFunctions() = 0; + virtual const AZStd::vector& GetListOfEBuses() = 0; + + }; + + class LuaSymbolsReporterBusTraits + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + }; + + using LuaSymbolsReporterRequestBus = AZ::EBus; + + } // namespace Script +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.cpp new file mode 100644 index 0000000000..81ba8ee398 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.cpp @@ -0,0 +1,475 @@ +/* + * 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 "LuaSymbolsReporterSystemComponent.h" + +namespace AzToolsFramework +{ + namespace Script + { + AZStd::string LuaPropertySymbol::ToString() const + { + return AZStd::string::format("%s [%s/%s]", + m_name.c_str(), + m_canRead ? "R" : "_", + m_canWrite ? "W" : "_"); + } + + void LuaPropertySymbol::Reflect(AZ::ReflectContext* context) + { + auto behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "script") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("name", BehaviorValueProperty(&LuaPropertySymbol::m_name)) + ->Property("canRead", BehaviorValueProperty(&LuaPropertySymbol::m_canRead)) + ->Property("canWrite", BehaviorValueProperty(&LuaPropertySymbol::m_canWrite)) + ->Method("ToString", &LuaPropertySymbol::ToString) + ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) + ; + } + } + + AZStd::string LuaMethodSymbol::ToString() const + { + return AZStd::string::format("%s(%s)", m_name.c_str(), m_debugArgumentInfo.c_str()); + } + + void LuaMethodSymbol::Reflect(AZ::ReflectContext* context) + { + auto behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "script") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("name", BehaviorValueProperty(&LuaMethodSymbol::m_name)) + ->Property("debugArgumentInfo", BehaviorValueProperty(&LuaMethodSymbol::m_debugArgumentInfo)) + ->Method("ToString", &LuaMethodSymbol::ToString) + ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) + ; + } + } + + AZStd::string LuaClassSymbol::ToString() const + { + return AZStd::string::format("%s [%s]", m_name.c_str(), m_typeId.ToString().c_str()); + } + + void LuaClassSymbol::Reflect(AZ::ReflectContext* context) + { + auto behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "script") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("name", BehaviorValueProperty(&LuaClassSymbol::m_name)) + ->Property("typeId", BehaviorValueProperty(&LuaClassSymbol::m_typeId)) + ->Property("properties", BehaviorValueProperty(&LuaClassSymbol::m_properties)) + ->Property("methods", BehaviorValueProperty(&LuaClassSymbol::m_methods)) + ->Method("ToString", &LuaClassSymbol::ToString) + ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) + ; + } + } + + AZStd::string LuaEBusSender::ToString() const + { + return AZStd::string::format("%s(%s) - [%s]", m_name.c_str(), m_debugArgumentInfo.c_str(), m_category.c_str()); + } + + void LuaEBusSender::Reflect(AZ::ReflectContext* context) + { + auto behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "script") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("name", BehaviorValueProperty(&LuaEBusSender::m_name)) + ->Property("debugArgumentInfo", BehaviorValueProperty(&LuaEBusSender::m_debugArgumentInfo)) + ->Property("category", BehaviorValueProperty(&LuaEBusSender::m_category)) + ->Method("ToString", &LuaEBusSender::ToString) + ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) + ; + } + } + + AZStd::string LuaEBusSymbol::ToString() const + { + auto boolToStr = +[](bool val) { return val ? "true" : "false"; }; + return AZStd::string::format("%s: canBroadcast(%s), canQueue(%s), hasHandler(%s)", + m_name.c_str(), + boolToStr(m_canBroadcast), boolToStr(m_canQueue), boolToStr(m_hasHandler)); + } + + void LuaEBusSymbol::Reflect(AZ::ReflectContext* context) + { + auto behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "script") + ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All) + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Property("name", BehaviorValueProperty(&LuaEBusSymbol::m_name)) + ->Property("canBroadcast", BehaviorValueProperty(&LuaEBusSymbol::m_canBroadcast)) + ->Property("canQueue", BehaviorValueProperty(&LuaEBusSymbol::m_canQueue)) + ->Property("hasHandler", BehaviorValueProperty(&LuaEBusSymbol::m_hasHandler)) + ->Property("senders", BehaviorValueProperty(&LuaEBusSymbol::m_senders)) + ->Method("ToString", &LuaEBusSymbol::ToString) + ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) + ; + } + } + + //! This local class helps us keeping private the sensitive data in LuaSymbolsReporterSystemComponent + //! Used inside the function pointers for several AZ::SciptContextDebug::Enumerate* functions. + class IntrusiveHelper + { + public: + static AZStd::vector& GetClassSymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedClassSymbols; } + static AZStd::unordered_map& GetClassUuidToIndexMap(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_classUuidToIndexMap; } + static AZStd::vector& GetGlobalPropertySymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedGlobalPropertySymbols; } + static AZStd::vector& GetGlobalFunctionSymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedGlobalFunctionSymbols; } + static AZStd::vector& GetEBusSymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedEbusSymbols; } + static AZStd::unordered_map& GetEBusNameToIndexMap(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_ebusNameToIndexMap; } + }; + + void LuaSymbolsReporterSystemComponent::Reflect(AZ::ReflectContext* context) + { + LuaPropertySymbol::Reflect(context); + LuaMethodSymbol::Reflect(context); + LuaClassSymbol::Reflect(context); + LuaEBusSender::Reflect(context); + LuaEBusSymbol::Reflect(context); + + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class() + ->Version(0); + + serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); + serializeContext->RegisterGenericType>(); + } + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("LuaSymbolsReporterBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Module, "script") + ->Event("GetListOfClasses", &LuaSymbolsReporterRequests::GetListOfClasses) + ->Event("GetListOfGlobalProperties", &LuaSymbolsReporterRequests::GetListOfGlobalProperties) + ->Event("GetListOfGlobalFunctions", &LuaSymbolsReporterRequests::GetListOfGlobalFunctions) + ->Event("GetListOfEBuses", &LuaSymbolsReporterRequests::GetListOfEBuses) + ; + } + } + + void LuaSymbolsReporterSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("LuaSymbolsReporterSystemService")); + } + + void LuaSymbolsReporterSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("LuaSymbolsReporterSystemService")); + } + + void LuaSymbolsReporterSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + required.push_back(AZ_CRC_CE("ScriptService")); + } + + void LuaSymbolsReporterSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + // No dependent services. + } + + void LuaSymbolsReporterSystemComponent::Activate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + LuaSymbolsReporterRequestBus::Handler::BusConnect(); + } + + void LuaSymbolsReporterSystemComponent::Deactivate() + { + LuaSymbolsReporterRequestBus::Handler::BusDisconnect(); + AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + } + + AZ::ScriptContext* LuaSymbolsReporterSystemComponent::InitScriptContext() + { + if (m_scriptContext) + { + return m_scriptContext; + } + + AZ::ScriptSystemRequestBus::BroadcastResult(m_scriptContext, &AZ::ScriptSystemRequests::GetContext, AZ::ScriptContextIds::DefaultScriptContextId); + return m_scriptContext; + } + + void LuaSymbolsReporterSystemComponent::LoadGlobalSymbols() + { + auto scriptContext = InitScriptContext(); + if (!scriptContext) + { + AZ_Error(LogName, false, "Invalid scriptContext"); + return; + } + + scriptContext->EnableDebug(); + + auto debugContext = scriptContext->GetDebugContext(); + if (!debugContext) + { + AZ_Error(LogName, false, "Invalid debugContext from scriptContext"); + return; + } + + auto enumMethodFunc = +[]([[maybe_unused]] const AZ::Uuid* classTypeId, const char* methodName, const char* debugArgumentInfo, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + auto& methodSymbols = IntrusiveHelper::GetGlobalFunctionSymbols(mySelf); + methodSymbols.push_back({}); + auto& methodSymbol = methodSymbols.back(); + methodSymbol.m_name = methodName; + if (debugArgumentInfo) + { + methodSymbol.m_debugArgumentInfo = debugArgumentInfo; + } + return true; + }; + + auto enumPropertyFunc = +[]([[maybe_unused]] const AZ::Uuid* classTypeId, const char* propertyName, bool canRead, bool canWrite, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + auto& propertySymbols = IntrusiveHelper::GetGlobalPropertySymbols(mySelf); + propertySymbols.push_back({}); + auto& propertySymbol = propertySymbols.back(); + propertySymbol.m_name = propertyName; + propertySymbol.m_canRead = canRead; + propertySymbol.m_canWrite = canWrite; + + return true; + }; + + debugContext->EnumRegisteredGlobals(enumMethodFunc, enumPropertyFunc, this); + + scriptContext->DisableDebug(); + } + + /////////////////////////////////////////////////////////////////////////// + /// LuaSymbolsReporterRequestBus::Handler + const AZStd::vector& LuaSymbolsReporterSystemComponent::GetListOfClasses() + { + if (!m_cachedClassSymbols.empty()) + { + return m_cachedClassSymbols; + } + + auto scriptContext = InitScriptContext(); + if (!scriptContext) + { + return m_cachedClassSymbols; + } + + scriptContext->EnableDebug(); + + auto debugContext = scriptContext->GetDebugContext(); + if (!debugContext) + { + return m_cachedClassSymbols; + } + + auto enumClassFunc = +[](const char* className, const AZ::Uuid& classTypeId, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + + auto& classSymbols = IntrusiveHelper::GetClassSymbols(mySelf); + classSymbols.push_back({}); + auto& classSymbol = classSymbols.back(); + classSymbol.m_name = className; + classSymbol.m_typeId = classTypeId; + + auto& uuidToClassMap = IntrusiveHelper::GetClassUuidToIndexMap(mySelf); + uuidToClassMap.emplace(classTypeId, classSymbols.size() - 1); + + return true; + }; + + auto enumMethodFunc = +[](const AZ::Uuid* classTypeId, const char* methodName, const char* debugArgumentInfo, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + auto& classUuidToIndexMap = IntrusiveHelper::GetClassUuidToIndexMap(mySelf); + auto itor = classUuidToIndexMap.find(*classTypeId); + if (itor == classUuidToIndexMap.end()) + { + AZ_Error(LogName, false, "Can not add method [%s] because class uuid [%s] is not registered", methodName, classTypeId->ToString().c_str()); + return false; + } + + auto classIndex = itor->second; + auto& classSymbols = IntrusiveHelper::GetClassSymbols(mySelf); + auto& classSymbol = classSymbols[classIndex]; + classSymbol.m_methods.push_back({}); + auto& methodSymbol = classSymbol.m_methods.back(); + methodSymbol.m_name = methodName; + if (debugArgumentInfo) + { + methodSymbol.m_debugArgumentInfo = debugArgumentInfo; + } + return true; + }; + + auto enumPropertyFunc = +[](const AZ::Uuid* classTypeId, const char* propertyName, bool canRead, bool canWrite, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + auto& classUuidToIndexMap = IntrusiveHelper::GetClassUuidToIndexMap(mySelf); + auto itor = classUuidToIndexMap.find(*classTypeId); + if (itor == classUuidToIndexMap.end()) + { + AZ_Error(LogName, false, "Can not add property [%s] because class uuid [%s] is not registered", propertyName, classTypeId->ToString().c_str()); + return false; + } + + auto classIndex = itor->second; + auto& classSymbols = IntrusiveHelper::GetClassSymbols(mySelf); + auto& classSymbol = classSymbols[classIndex]; + classSymbol.m_properties.push_back({}); + auto& propertySymbol = classSymbol.m_properties.back(); + propertySymbol.m_name = propertyName; + propertySymbol.m_canRead = canRead; + propertySymbol.m_canWrite = canWrite; + + return true; + }; + + debugContext->EnumRegisteredClasses(enumClassFunc, enumMethodFunc, enumPropertyFunc, this); + + scriptContext->DisableDebug(); + + return m_cachedClassSymbols; + } + + const AZStd::vector& LuaSymbolsReporterSystemComponent::GetListOfGlobalProperties() + { + if (!m_cachedGlobalPropertySymbols.empty()) + { + return m_cachedGlobalPropertySymbols; + } + + LoadGlobalSymbols(); + + return m_cachedGlobalPropertySymbols; + } + + const AZStd::vector& LuaSymbolsReporterSystemComponent::GetListOfGlobalFunctions() + { + if (!m_cachedGlobalFunctionSymbols.empty()) + { + return m_cachedGlobalFunctionSymbols; + } + + LoadGlobalSymbols(); + + return m_cachedGlobalFunctionSymbols; + } + + const AZStd::vector& LuaSymbolsReporterSystemComponent::GetListOfEBuses() + { + if (!m_cachedEbusSymbols.empty()) + { + return m_cachedEbusSymbols; + } + + auto scriptContext = InitScriptContext(); + if (!scriptContext) + { + return m_cachedEbusSymbols; + } + + scriptContext->EnableDebug(); + + auto debugContext = scriptContext->GetDebugContext(); + if (!debugContext) + { + return m_cachedEbusSymbols; + } + + auto enumEBusFunc = +[](const AZStd::string& ebusName, bool canBroadcast, bool canQueue, bool hasHandler, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + + auto& ebusSymbols = IntrusiveHelper::GetEBusSymbols(mySelf); + ebusSymbols.push_back({}); + auto& ebusSymbol = ebusSymbols.back(); + ebusSymbol.m_name = ebusName; + ebusSymbol.m_canBroadcast = canBroadcast; + ebusSymbol.m_canQueue = canQueue; + ebusSymbol.m_hasHandler = hasHandler; + + auto& nameToIndexMap = IntrusiveHelper::GetEBusNameToIndexMap(mySelf); + nameToIndexMap.emplace(ebusName, ebusSymbols.size() - 1); + + return true; + }; + + auto enumEBusSenderFunc = +[](const AZStd::string& ebusName, const AZStd::string& senderName, const AZStd::string& debugArgumentInfo, const AZStd::string& category, void* userData) -> bool + { + auto& mySelf = *reinterpret_cast(userData); + auto& nameToIndexMap = IntrusiveHelper::GetEBusNameToIndexMap(mySelf); + auto itor = nameToIndexMap.find(ebusName); + if (itor == nameToIndexMap.end()) + { + AZ_Error(LogName, false, "Can not add ebus sender [%s] because ebus [%s] is not registered", senderName.c_str(), ebusName.c_str()); + return false; + } + + auto ebusIndex = itor->second; + auto& ebusSymbols = IntrusiveHelper::GetEBusSymbols(mySelf); + auto& ebusSymbol = ebusSymbols[ebusIndex]; + + ebusSymbol.m_senders.push_back({}); + auto& ebusSender = ebusSymbol.m_senders.back(); + ebusSender.m_name = senderName; + ebusSender.m_debugArgumentInfo = debugArgumentInfo; + ebusSender.m_category = category; + return true; + }; + + debugContext->EnumRegisteredEBuses(enumEBusFunc, enumEBusSenderFunc, this); + + scriptContext->DisableDebug(); + + return m_cachedEbusSymbols; + } + /////////////////////////////////////////////////////////////////////////// + + } //namespace Script +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h new file mode 100644 index 0000000000..2467c82ad7 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h @@ -0,0 +1,73 @@ +/* + * 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 + +#include +#include + +#include + +namespace AzToolsFramework +{ + namespace Script + { + /// System component for LuaSymbolsReporterRequestBus + class LuaSymbolsReporterSystemComponent + : public AZ::Component + , public LuaSymbolsReporterRequestBus::Handler + , private AzToolsFramework::EditorEvents::Bus::Handler + { + public: + AZ_COMPONENT(LuaSymbolsReporterSystemComponent, "{DB8D95BA-FECF-4D81-A45C-8C05E706E2AC}"); + static void Reflect(AZ::ReflectContext* context); + + static constexpr char LogName[] = "LuaSymbolsReporter"; + + LuaSymbolsReporterSystemComponent() = default; + ~LuaSymbolsReporterSystemComponent() = default; + + /////////////////////////////////////////////////////////////////////////// + /// LuaSymbolsReporterRequestBus::Handler + const AZStd::vector& GetListOfClasses() override; + const AZStd::vector& GetListOfGlobalProperties() override; + const AZStd::vector& GetListOfGlobalFunctions() override; + const AZStd::vector& GetListOfEBuses() override; + /////////////////////////////////////////////////////////////////////////// + + private: + friend class IntrusiveHelper; + + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + // AZ::Component + void Activate() override; + void Deactivate() override; + + AZ::ScriptContext* InitScriptContext(); + void LoadGlobalSymbols(); + + AZ::ScriptContext* m_scriptContext = nullptr; + + AZStd::vector m_cachedClassSymbols; + // The key is a class uuid, the value is the index in @m_cachedClassSymbols + AZStd::unordered_map m_classUuidToIndexMap; + + AZStd::vector m_cachedGlobalPropertySymbols; + AZStd::vector m_cachedGlobalFunctionSymbols; + + AZStd::vector m_cachedEbusSymbols; + + // The key is the ebus name, the value is the index in @m_cachedEbusSymbols + AZStd::unordered_map m_ebusNameToIndexMap; + + }; + } // namespace Script +} // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index b57eedcd81..286ef97418 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -770,6 +770,9 @@ set(FILES PythonTerminal/ScriptTermDialog.ui Input/QtEventToAzInputManager.h Input/QtEventToAzInputManager.cpp + Script/LuaSymbolsReporterBus.h + Script/LuaSymbolsReporterSystemComponent.h + Script/LuaSymbolsReporterSystemComponent.cpp ) # Prevent the following files from being grouped in UNITY builds From ce3e998a328de5609c1d7b75e4867bd3bbb94ba8 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Mon, 25 Oct 2021 13:48:17 -0700 Subject: [PATCH 057/200] Add xcb input dev packages (#4962) Signed-off-by: Mike Chang Signed-off-by: Gene Walters --- .../Platform/Linux/package-list.ubuntu-bionic.txt | 7 ++++++- .../Platform/Linux/package-list.ubuntu-focal.txt | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt index 625909e214..a09d823950 100644 --- a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt +++ b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-bionic.txt @@ -12,7 +12,12 @@ libxcb-xinerama0 # For Qt plugins at runtime libxcb-xinput0 # For Qt plugins at runtime libfontconfig1-dev # For Qt plugins at runtime libcurl4-openssl-dev # For HttpRequestor -libsdl2-dev # for WWise/Audio +libsdl2-dev # For WWise/Audio +libxcb-xkb-dev # For xcb keyboard input +libxkbcommon-x11-dev # For xcb keyboard input +libxkbcommon-dev # For xcb keyboard input +libxcb-xfixes0-dev # For mouse input +libxcb-xinput-dev # For mouse input zlib1g-dev mesa-common-dev diff --git a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt index 2cbbe58b38..e0e03cda90 100644 --- a/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt +++ b/scripts/build/build_node/Platform/Linux/package-list.ubuntu-focal.txt @@ -16,5 +16,7 @@ libsdl2-dev # for WWise/Audio libxcb-xkb-dev # For xcb keyboard input libxkbcommon-x11-dev # For xcb keyboard input libxkbcommon-dev # For xcb keyboard input +libxcb-xfixes0-dev # For mouse input +libxcb-xinput-dev # For mouse input zlib1g-dev mesa-common-dev From 6c67996f857374e1290cb46a3596b17bac71a87d Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 25 Oct 2021 14:57:53 -0700 Subject: [PATCH 058/200] Set Project Manager minimum height 700px (#4970) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> Signed-off-by: Gene Walters --- Code/Tools/ProjectManager/Resources/ProjectManager.qss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 6694168f2b..db0ec7e91a 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -9,7 +9,7 @@ QMainWindow { #ScreensCtrl { min-width:1200px; - min-height:800px; + min-height:700px; } QPushButton:focus { From f162ae2dc0f49a56d9c2a7c397de77d396121857 Mon Sep 17 00:00:00 2001 From: Jonny Galloway Date: Mon, 25 Oct 2021 18:18:27 -0500 Subject: [PATCH 059/200] Scaffold PythonGem template (#4888) * Renamed ctest_pytest.ini to pytest.ini so it is used by default, added TestSuite_ as collection file (#4822) * Fixed warnings of unused marks, renamed ctest_pytest.ini to pytest.ini to better consistency on runs * Fixed some test suites to run propertly * Fix missing arguments * Fixed missing cmakelists and renamed missing file * Temp disable editor_testing_tests as timeout in jenkins Signed-off-by: Jonny Gallowy * scaffold PythonGem template Signed-off-by: Jonny Gallowy * CustomTool was not added to CMakeLists Signed-off-by: Jonny Gallowy * Update Templates/PythonGem/Template/Code/CMakeLists.txt makes sense thank you for the help Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: Jonny Gallowy * Update Templates/PythonGem/Template/Code/CMakeLists.txt Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: Jonny Gallowy * Delete ${NameLower}_tests_files.cmake Signed-off-by: Jonny Gallowy * suggested changes made Signed-off-by: Jonny Gallowy * cleanup not needed files Signed-off-by: Jonny Gallowy * fix up template.json Signed-off-by: Jonny Gallowy * made a correction Signed-off-by: Jonny Gallowy * made a correction Signed-off-by: Jonny Gallowy * fixes Signed-off-by: Jonny Gallowy * fixes Signed-off-by: Jonny Gallowy * more fixes, fixed a file name Signed-off-by: Jonny Gallowy * Added helper method to az_qt_helpers for retrieving the main window instance. Signed-off-by: Chris Galvan * additional fixes Signed-off-by: Jonny Gallowy * Fix for AP trowing errors at boot (can not get mainwindow) Signed-off-by: Jonny Gallowy * Added missing EBus connect/disconnect calls in the EditorSystemComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * additional fix up Signed-off-by: Jonny Gallowy * adding dialog internals Signed-off-by: Jonny Gallowy Co-authored-by: AMZN-AlexOteiza <82234181+AMZN-AlexOteiza@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Co-authored-by: Chris Galvan Signed-off-by: Gene Walters --- Templates/CMakeLists.txt | 2 + Templates/PythonGem/Template/CMakeLists.txt | 14 ++ .../Code/${NameLower}_editor_files.cmake | 14 ++ .../${NameLower}_editor_shared_files.cmake | 11 + .../${NameLower}_editor_tests_files.cmake | 11 + .../PythonGem/Template/Code/CMakeLists.txt | 76 ++++++ .../Code/Include/${Name}/${Name}Bus.h | 40 ++++ .../Linux/${NameLower}_linux_files.cmake | 15 ++ .../${NameLower}_shared_linux_files.cmake | 15 ++ .../Code/Platform/Linux/PAL_linux.cmake | 11 + .../Platform/Mac/${NameLower}_mac_files.cmake | 15 ++ .../Mac/${NameLower}_shared_mac_files.cmake | 15 ++ .../Template/Code/Platform/Mac/PAL_mac.cmake | 11 + .../${NameLower}_shared_windows_files.cmake | 15 ++ .../Windows/${NameLower}_windows_files.cmake | 15 ++ .../Code/Platform/Windows/PAL_windows.cmake | 11 + .../Code/Source/${Name}EditorModule.cpp | 47 ++++ .../Source/${Name}EditorSystemComponent.cpp | 70 ++++++ .../Source/${Name}EditorSystemComponent.h | 42 ++++ .../Code/Source/${Name}ModuleInterface.h | 36 +++ .../Template/Code/Tests/${Name}EditorTest.cpp | 13 ++ .../Editor/Scripts/${NameLower}_dialog.py | 46 ++++ .../Template/Editor/Scripts/__init__.py | 9 + .../Template/Editor/Scripts/bootstrap.py | 117 ++++++++++ Templates/PythonGem/Template/gem.json | 16 ++ Templates/PythonGem/Template/preview.png | 3 + Templates/PythonGem/template.json | 216 ++++++++++++++++++ 27 files changed, 906 insertions(+) create mode 100644 Templates/PythonGem/Template/CMakeLists.txt create mode 100644 Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake create mode 100644 Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake create mode 100644 Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake create mode 100644 Templates/PythonGem/Template/Code/CMakeLists.txt create mode 100644 Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h create mode 100644 Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake create mode 100644 Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h create mode 100644 Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h create mode 100644 Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp create mode 100644 Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py create mode 100644 Templates/PythonGem/Template/Editor/Scripts/__init__.py create mode 100644 Templates/PythonGem/Template/Editor/Scripts/bootstrap.py create mode 100644 Templates/PythonGem/Template/gem.json create mode 100644 Templates/PythonGem/Template/preview.png create mode 100644 Templates/PythonGem/template.json diff --git a/Templates/CMakeLists.txt b/Templates/CMakeLists.txt index 1a3a45b5ec..84a708989a 100644 --- a/Templates/CMakeLists.txt +++ b/Templates/CMakeLists.txt @@ -9,6 +9,8 @@ ly_install_directory( DIRECTORIES AssetGem + CustomTool + PythonGem DefaultGem DefaultProject MinimalProject diff --git a/Templates/PythonGem/Template/CMakeLists.txt b/Templates/PythonGem/Template/CMakeLists.txt new file mode 100644 index 0000000000..d61bbd9e7d --- /dev/null +++ b/Templates/PythonGem/Template/CMakeLists.txt @@ -0,0 +1,14 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR}) +set(o3de_gem_json ${o3de_gem_path}/gem.json) +o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name") +o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) + +add_subdirectory(Code) diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake b/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake new file mode 100644 index 0000000000..8362d37f52 --- /dev/null +++ b/Templates/PythonGem/Template/Code/${NameLower}_editor_files.cmake @@ -0,0 +1,14 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Include/${Name}/${Name}Bus.h + Source/${Name}ModuleInterface.h + Source/${Name}EditorSystemComponent.cpp + Source/${Name}EditorSystemComponent.h +) diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake b/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake new file mode 100644 index 0000000000..2d4ceae97d --- /dev/null +++ b/Templates/PythonGem/Template/Code/${NameLower}_editor_shared_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Source/${Name}EditorModule.cpp +) diff --git a/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake b/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake new file mode 100644 index 0000000000..ff45c2fc1c --- /dev/null +++ b/Templates/PythonGem/Template/Code/${NameLower}_editor_tests_files.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(FILES + Tests/${Name}EditorTest.cpp +) diff --git a/Templates/PythonGem/Template/Code/CMakeLists.txt b/Templates/PythonGem/Template/Code/CMakeLists.txt new file mode 100644 index 0000000000..b7a5ac89a9 --- /dev/null +++ b/Templates/PythonGem/Template/Code/CMakeLists.txt @@ -0,0 +1,76 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Currently we are in the Code folder: ${CMAKE_CURRENT_LIST_DIR} +# Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} +# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform +# in which case it will see if that platform is present here or in the restricted folder. +# i.e. It could here in our gem : Gems/${Name}/Code/Platform/ or +# //Gems/${Name}/Code +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) + +# Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the +# traits for this platform. Traits for a platform are defines for things like whether or not something in this gem +# is supported by this platform. +include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + + +# If we are on a host platform, we want to add the host tools targets like the ${Name}.Editor target which +# will also depend on ${Name}.Static +if(PAL_TRAIT_BUILD_HOST_TOOLS) + ly_add_target( + NAME ${Name}.Editor.Static STATIC + NAMESPACE Gem + FILES_CMAKE + ${NameLower}_editor_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + AZ::AzToolsFramework + ) + + ly_add_target( + NAME ${Name}.Editor GEM_MODULE + NAMESPACE Gem + AUTOMOC + FILES_CMAKE + ${NameLower}_editor_shared_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PUBLIC + Gem::${Name}.Editor.Static + ) + + # By default, we will specify that the above target ${Name} would be used by + # Tool and Builder type targets when this gem is enabled. If you don't want it + # active in Tools or Builders by default, delete one of both of the following lines: + ly_create_alias(NAME ${Name}.Tools NAMESPACE Gem TARGETS Gem::${Name}.Editor) + ly_create_alias(NAME ${Name}.Builders NAMESPACE Gem TARGETS Gem::${Name}.Editor) + + +endif() + +################################################################################ +# Tests +################################################################################ +# See if globally, tests are supported +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + # We globally support tests, see if we support tests on this platform for ${Name}.Static + + # If we are a host platform we want to add tools test like editor tests here + if(PAL_TRAIT_BUILD_HOST_TOOLS) + endif() +endif() diff --git a/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h b/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h new file mode 100644 index 0000000000..d09bb2b009 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Include/${Name}/${Name}Bus.h @@ -0,0 +1,40 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#pragma once + +#include +#include + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}Requests + { + public: + AZ_RTTI(${SanitizedCppName}Requests, "{${Random_Uuid}}"); + virtual ~${SanitizedCppName}Requests() = default; + // Put your public methods here + }; + + class ${SanitizedCppName}BusTraits + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + }; + + using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>; + using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>; + +} // namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake new file mode 100644 index 0000000000..2f58a2e6f5 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_linux_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Linux +# i.e. ../Source/Linux/${Name}Linux.cpp +# ../Source/Linux/${Name}Linux.h +# ../Include/Linux/${Name}Linux.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake new file mode 100644 index 0000000000..2f58a2e6f5 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Linux/${NameLower}_shared_linux_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Linux +# i.e. ../Source/Linux/${Name}Linux.cpp +# ../Source/Linux/${Name}Linux.h +# ../Include/Linux/${Name}Linux.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake b/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Linux/PAL_linux.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake new file mode 100644 index 0000000000..1cf737a2f1 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_mac_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Mac +# i.e. ../Source/Mac/${Name}Mac.cpp +# ../Source/Mac/${Name}Mac.h +# ../Include/Mac/${Name}Mac.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake new file mode 100644 index 0000000000..1cf737a2f1 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Mac/${NameLower}_shared_mac_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Mac +# i.e. ../Source/Mac/${Name}Mac.cpp +# ../Source/Mac/${Name}Mac.h +# ../Include/Mac/${Name}Mac.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake b/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Mac/PAL_mac.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake new file mode 100644 index 0000000000..712aad1207 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_shared_windows_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Windows +# i.e. ../Source/Windows/${Name}Windows.cpp +# ../Source/Windows/${Name}Windows.h +# ../Include/Windows/${Name}Windows.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake new file mode 100644 index 0000000000..712aad1207 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Windows/${NameLower}_windows_files.cmake @@ -0,0 +1,15 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +# Platform specific files for Windows +# i.e. ../Source/Windows/${Name}Windows.cpp +# ../Source/Windows/${Name}Windows.h +# ../Include/Windows/${Name}Windows.h + +set(FILES +) diff --git a/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake b/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake new file mode 100644 index 0000000000..0abcd887e8 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Platform/Windows/PAL_windows.cmake @@ -0,0 +1,11 @@ +# {BEGIN_LICENSE} +# 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 +# +# {END_LICENSE} + +set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE) +set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE) \ No newline at end of file diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp b/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp new file mode 100644 index 0000000000..644c513747 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}EditorModule.cpp @@ -0,0 +1,47 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include <${Name}ModuleInterface.h> +#include <${Name}EditorSystemComponent.h> + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}EditorModule + : public ${SanitizedCppName}ModuleInterface + { + public: + AZ_RTTI(${SanitizedCppName}EditorModule, "${ModuleClassId}", ${SanitizedCppName}ModuleInterface); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}EditorModule, AZ::SystemAllocator, 0); + + ${SanitizedCppName}EditorModule() + { + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. + // Add ALL components descriptors associated with this gem to m_descriptors. + // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext. + // This happens through the [MyComponent]::Reflect() function. + m_descriptors.insert(m_descriptors.end(), { + ${SanitizedCppName}EditorSystemComponent::CreateDescriptor(), + }); + } + + /** + * Add required SystemComponents to the SystemEntity. + * Non-SystemComponents should not be added here + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList { + azrtti_typeid<${SanitizedCppName}EditorSystemComponent>(), + }; + } + }; +}// namespace ${SanitizedCppName} + +AZ_DECLARE_MODULE_CLASS(Gem_${SanitizedCppName}, ${SanitizedCppName}::${SanitizedCppName}EditorModule) diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp new file mode 100644 index 0000000000..1493c98e68 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.cpp @@ -0,0 +1,70 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ + // {END_LICENSE} + +#include +#include <${Name}EditorSystemComponent.h> + +namespace ${SanitizedCppName} +{ + void ${SanitizedCppName}EditorSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context)) + { + serializeContext->Class<${SanitizedCppName}EditorSystemComponent, AZ::Component>(); + } + } + + ${SanitizedCppName}EditorSystemComponent::${SanitizedCppName}EditorSystemComponent() + { + if (${SanitizedCppName}Interface::Get() == nullptr) + { + ${SanitizedCppName}Interface::Register(this); + } + } + + ${SanitizedCppName}EditorSystemComponent::~${SanitizedCppName}EditorSystemComponent() + { + if (${SanitizedCppName}Interface::Get() == this) + { + ${SanitizedCppName}Interface::Unregister(this); + } + } + + void ${SanitizedCppName}EditorSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + { + provided.push_back(AZ_CRC_CE("${SanitizedCppName}EditorService")); + } + + void ${SanitizedCppName}EditorSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) + { + incompatible.push_back(AZ_CRC_CE("${SanitizedCppName}EditorService")); + } + + void ${SanitizedCppName}EditorSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required) + { + } + + void ${SanitizedCppName}EditorSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) + { + } + + void ${SanitizedCppName}EditorSystemComponent::Activate() + { + ${SanitizedCppName}RequestBus::Handler::BusConnect(); + AzToolsFramework::EditorEvents::Bus::Handler::BusConnect(); + } + + void ${SanitizedCppName}EditorSystemComponent::Deactivate() + { + AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect(); + ${SanitizedCppName}RequestBus::Handler::BusDisconnect(); + } + +} // namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h new file mode 100644 index 0000000000..1db8725a9e --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}EditorSystemComponent.h @@ -0,0 +1,42 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ + // {END_LICENSE} + +#pragma once +#include +#include <${Name}/${Name}Bus.h> + +#include + +namespace ${SanitizedCppName} +{ + /// System component for ${SanitizedCppName} editor + class ${SanitizedCppName}EditorSystemComponent + : public ${SanitizedCppName}RequestBus::Handler + , private AzToolsFramework::EditorEvents::Bus::Handler + , public AZ::Component + { + public: + AZ_COMPONENT(${SanitizedCppName}EditorSystemComponent, "${EditorSysCompClassId}"); + static void Reflect(AZ::ReflectContext* context); + + ${SanitizedCppName}EditorSystemComponent(); + ~${SanitizedCppName}EditorSystemComponent(); + + private: + static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); + static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); + static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent); + + // AZ::Component + void Activate(); + void Deactivate(); + }; +} // namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h b/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h new file mode 100644 index 0000000000..4ddfc9c007 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Source/${Name}ModuleInterface.h @@ -0,0 +1,36 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include +#include + +namespace ${SanitizedCppName} +{ + class ${SanitizedCppName}ModuleInterface + : public AZ::Module + { + public: + AZ_RTTI(${SanitizedCppName}ModuleInterface, "{${Random_Uuid}}", AZ::Module); + AZ_CLASS_ALLOCATOR(${SanitizedCppName}ModuleInterface, AZ::SystemAllocator, 0); + + ${SanitizedCppName}ModuleInterface() + { + } + + /** + * Add required SystemComponents to the SystemEntity. + */ + AZ::ComponentTypeList GetRequiredSystemComponents() const override + { + return AZ::ComponentTypeList{ + }; + } + }; +}// namespace ${SanitizedCppName} diff --git a/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp b/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp new file mode 100644 index 0000000000..9b84575fa0 --- /dev/null +++ b/Templates/PythonGem/Template/Code/Tests/${Name}EditorTest.cpp @@ -0,0 +1,13 @@ +// {BEGIN_LICENSE} +/* + * 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 + * + */ +// {END_LICENSE} + +#include + +AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); diff --git a/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py b/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py new file mode 100644 index 0000000000..39515711ae --- /dev/null +++ b/Templates/PythonGem/Template/Editor/Scripts/${NameLower}_dialog.py @@ -0,0 +1,46 @@ +""" +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 +""" +# ------------------------------------------------------------------------- +"""${SanitizedCppName}\\editor\\scripts\\${SanitizedCppName}_dialog.py +Generated from O3DE PythonGem Template""" + +import azlmbr +from shiboken2 import wrapInstance, getCppPointer +from PySide2 import QtCore, QtWidgets, QtGui +from PySide2.QtCore import QEvent, Qt +from PySide2.QtWidgets import QVBoxLayout, QAction, QDialog, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTreeWidget, QTreeWidgetItem, QWidget, QAbstractButton + +# Once PySide2 has been bootstrapped, register our ${SanitizedCppName}Dialog with the Editor + +class ${SanitizedCppName}Dialog(QDialog): + def __init__(self, parent=None): + super(${SanitizedCppName}Dialog, self).__init__(parent) + + self.setObjectName("${SanitizedCppName}Dialog") + + self.setWindowTitle("HelloWorld, ${SanitizedCppName} Dialog") + + self.mainLayout = QVBoxLayout(self) + + self.introLabel = QLabel("Put your cool stuff here!") + + self.mainLayout.addWidget(self.introLabel, 0, Qt.AlignCenter) + + self.helpText = str("For help getting started," + "visit the UI Development documentation
" + "or come ask a question in the sig-ui-ux channel on Discord") + + self.helpLabel = QLabel() + self.helpLabel.setTextFormat(Qt.RichText) + self.helpLabel.setText(self.helpText) + self.helpLabel.setOpenExternalLinks(True) + + self.mainLayout.addWidget(self.helpLabel, 0, Qt.AlignCenter) + + self.setLayout(self.mainLayout) + + return \ No newline at end of file diff --git a/Templates/PythonGem/Template/Editor/Scripts/__init__.py b/Templates/PythonGem/Template/Editor/Scripts/__init__.py new file mode 100644 index 0000000000..b5da0c7ff0 --- /dev/null +++ b/Templates/PythonGem/Template/Editor/Scripts/__init__.py @@ -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 +""" +# ------------------------------------------------------------------------- + +__ALL__ = ['bootstrap','${NameLower}_dialog'] \ No newline at end of file diff --git a/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py b/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py new file mode 100644 index 0000000000..060116d36c --- /dev/null +++ b/Templates/PythonGem/Template/Editor/Scripts/bootstrap.py @@ -0,0 +1,117 @@ +""" +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 +""" +# ------------------------------------------------------------------------- +"""${SanitizedCppName}\\editor\\scripts\\boostrap.py +Generated from O3DE PythonGem Template""" + +import azlmbr +import az_qt_helpers +from PySide2 import QtCore, QtWidgets, QtGui +from PySide2.QtCore import QEvent, Qt +from PySide2.QtWidgets import QMainWindow, QAction, QDialog, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTreeWidget, QTreeWidgetItem, QWidget, QAbstractButton +# ------------------------------------------------------------------------- + + +# ------------------------------------------------------------------------- +class SampleUI(QtWidgets.QDialog): + """Lightweight UI Test Class created a button""" + def __init__(self, parent, title='Not Set'): + super(SampleUI, self).__init__(parent) + self.setWindowTitle(title) + self.initUI() + + def initUI(self): + mainLayout = QtWidgets.QHBoxLayout() + testBtn = QtWidgets.QPushButton("I am just a Button man!") + mainLayout.addWidget(testBtn) + self.setLayout(mainLayout) +# ------------------------------------------------------------------------- + +if __name__ == "__main__": + print("${SanitizedCppName}.boostrap, Generated from O3DE PythonGem Template") + + # --------------------------------------------------------------------- + # validate pyside before continuing + try: + azlmbr.qt.QtForPythonRequestBus(azlmbr.bus.Broadcast, 'IsActive') + params = azlmbr.qt.QtForPythonRequestBus(azlmbr.bus.Broadcast, 'GetQtBootstrapParameters') + params is not None and params.mainWindowId is not 0 + from PySide2 import QtWidgets + except Exception as e: + _LOGGER.error(f'Pyside not available, exception: {e}') + raise e + + # keep going, import the other PySide2 bits we will use + from PySide2 import QtGui + from PySide2.QtCore import Slot + from shiboken2 import wrapInstance, getCppPointer + + # Get our Editor main window + _widget_main_window = None + try: + _widget_main_window = az_qt_helpers.get_editor_main_window() + except: + pass # may be booting in the AP? + # --------------------------------------------------------------------- + + + # --------------------------------------------------------------------- + if _widget_main_window: + # creat a custom menu + _tag_str = '${SanitizedCppName}' + + # create our own menuBar + ${SanitizedCppName}_menu = _widget_main_window.menuBar().addMenu(f"&{_tag_str}") + + # nest a menu for util/tool launching + ${SanitizedCppName}_launch_menu = ${SanitizedCppName}_menu.addMenu("examples") + else: + print('No O3DE MainWindow') + # --------------------------------------------------------------------- + + + # --------------------------------------------------------------------- + if _widget_main_window: + # (1) add the first SampleUI + action_launch_sample_ui = ${SanitizedCppName}_launch_menu.addAction("O3DE:SampleUI") + + @Slot() + def clicked_sample_ui(): + while 1: # simple PySide2 test, set to 0 to disable + ui = SampleUI(parent=_widget_main_window, title='O3DE:SampleUI') + ui.show() + break + return + # Add click event to menu bar + action_launch_sample_ui.triggered.connect(clicked_sample_ui) + # --------------------------------------------------------------------- + + + # --------------------------------------------------------------------- + if _widget_main_window: + # (1) and custom external module Qwidget + action_launch_${SanitizedCppName}_dialog = ${SanitizedCppName}_launch_menu.addAction("O3DE:${SanitizedCppName}_dialog") + + @Slot() + def clicked_${SanitizedCppName}_dialog(): + while 1: # simple PySide2 test, set to 0 to disable + try: + import az_qt_helpers + from ${NameLower}_dialog import ${SanitizedCppName}Dialog + az_qt_helpers.register_view_pane('${SanitizedCppName} Popup', ${SanitizedCppName}Dialog) + except Exception as e: + print(f'Error: {e}') + print('Skipping register our ${SanitizedCppName}Dialog with the Editor.') + ${SanitizedCppName}_dialog = ${SanitizedCppName}Dialog(parent=_widget_main_window) + ${SanitizedCppName}_dialog.show() + break + return + # Add click event to menu bar + action_launch_${SanitizedCppName}_dialog.triggered.connect(clicked_${SanitizedCppName}_dialog) + # --------------------------------------------------------------------- + + # end \ No newline at end of file diff --git a/Templates/PythonGem/Template/gem.json b/Templates/PythonGem/Template/gem.json new file mode 100644 index 0000000000..353ad6bf8d --- /dev/null +++ b/Templates/PythonGem/Template/gem.json @@ -0,0 +1,16 @@ +{ + "gem_name": "${Name}", + "display_name": "${Name}", + "license": "What license ${Name} uses goes here: i.e. https://opensource.org/licenses/MIT", + "origin": "The primary repo for ${Name} goes here: i.e. http://www.mydomain.com", + "type": "Code", + "summary": "A short description of ${Name}.", + "canonical_tags": [ + "Gem" + ], + "user_tags": [ + "${Name}" + ], + "icon_path": "preview.png", + "requirements": "" +} diff --git a/Templates/PythonGem/Template/preview.png b/Templates/PythonGem/Template/preview.png new file mode 100644 index 0000000000..0f393ac886 --- /dev/null +++ b/Templates/PythonGem/Template/preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ac9dd09bde78f389e3725ac49d61eff109857e004840bc0bc3881739df9618d +size 2217 diff --git a/Templates/PythonGem/template.json b/Templates/PythonGem/template.json new file mode 100644 index 0000000000..75be757abb --- /dev/null +++ b/Templates/PythonGem/template.json @@ -0,0 +1,216 @@ +{ + "template_name": "PythonGem", + "restricted_name": "o3de", + "restricted_platform_relative_path": "Templates", + "origin": "The primary repo for PythonGem goes here: i.e. http://www.mydomain.com", + "license": "What license PythonGem uses goes here: i.e. https://opensource.org/licenses/MIT", + "display_name": "PythonGem", + "summary": "A short description of PythonGem.", + "canonical_tags": [], + "user_tags": [ + "PythonGem" + ], + "icon_path": "preview.png", + "copyFiles": [ + { + "file": "CMakeLists.txt", + "origin": "CMakeLists.txt", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_files.cmake", + "origin": "Code/${NameLower}_editor_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_shared_files.cmake", + "origin": "Code/${NameLower}_editor_shared_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/${NameLower}_editor_tests_files.cmake", + "origin": "Code/${NameLower}_editor_tests_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/CMakeLists.txt", + "origin": "Code/CMakeLists.txt", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Include/${Name}/${Name}Bus.h", + "origin": "Code/Include/${Name}/${Name}Bus.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/${NameLower}_linux_files.cmake", + "origin": "Code/Platform/Linux/${NameLower}_linux_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "origin": "Code/Platform/Linux/${NameLower}_shared_linux_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Linux/PAL_linux.cmake", + "origin": "Code/Platform/Linux/PAL_linux.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/${NameLower}_mac_files.cmake", + "origin": "Code/Platform/Mac/${NameLower}_mac_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "origin": "Code/Platform/Mac/${NameLower}_shared_mac_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Mac/PAL_mac.cmake", + "origin": "Code/Platform/Mac/PAL_mac.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "origin": "Code/Platform/Windows/${NameLower}_shared_windows_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/${NameLower}_windows_files.cmake", + "origin": "Code/Platform/Windows/${NameLower}_windows_files.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Platform/Windows/PAL_windows.cmake", + "origin": "Code/Platform/Windows/PAL_windows.cmake", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorModule.cpp", + "origin": "Code/Source/${Name}EditorModule.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorSystemComponent.cpp", + "origin": "Code/Source/${Name}EditorSystemComponent.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}EditorSystemComponent.h", + "origin": "Code/Source/${Name}EditorSystemComponent.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Source/${Name}ModuleInterface.h", + "origin": "Code/Source/${Name}ModuleInterface.h", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Code/Tests/${Name}EditorTest.cpp", + "origin": "Code/Tests/${Name}EditorTest.cpp", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Editor/Scripts/__init__.py", + "origin": "Editor/Scripts/__init__.py", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Editor/Scripts/bootstrap.py", + "origin": "Editor/Scripts/bootstrap.py", + "isTemplated": true, + "isOptional": false + }, + { + "file": "Editor/Scripts/${NameLower}_dialog.py", + "origin": "Editor/Scripts/${NameLower}_dialog.py", + "isTemplated": true, + "isOptional": false + }, + { + "file": "gem.json", + "origin": "gem.json", + "isTemplated": true, + "isOptional": false + }, + { + "file": "preview.png", + "origin": "preview.png", + "isTemplated": false, + "isOptional": false + } + ], + "createDirectories": [ + { + "dir": "Assets", + "origin": "Assets" + }, + { + "dir": "Code", + "origin": "Code" + }, + { + "dir": "Editor", + "origin": "Editor" + }, + { + "dir": "Editor/Scripts", + "origin": "Editor/Scripts" + }, + { + "dir": "Code/Include", + "origin": "Code/Include" + }, + { + "dir": "Code/Include/${Name}", + "origin": "Code/Include/${Name}" + }, + { + "dir": "Code/Platform", + "origin": "Code/Platform" + }, + { + "dir": "Code/Platform/Linux", + "origin": "Code/Platform/Linux" + }, + { + "dir": "Code/Platform/Mac", + "origin": "Code/Platform/Mac" + }, + { + "dir": "Code/Platform/Windows", + "origin": "Code/Platform/Windows" + }, + { + "dir": "Code/Source", + "origin": "Code/Source" + }, + { + "dir": "Code/Tests", + "origin": "Code/Tests" + } + ] +} From 89177790f528e8490a5c9b5a12acc8514a0f09c4 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:33:32 -0700 Subject: [PATCH 060/200] Disable custom titlebar on Mac, Linux, fix resize (#4973) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> Signed-off-by: Gene Walters --- Code/Tools/ProjectManager/CMakeLists.txt | 1 + .../Platform/Linux/PAL_linux_files.cmake | 2 ++ .../Platform/Linux/ProjectManager_Traits_Linux.h | 11 +++++++++++ .../Platform/Linux/ProjectManager_Traits_Platform.h | 11 +++++++++++ .../ProjectManager/Platform/Mac/PAL_mac_files.cmake | 2 ++ .../Platform/Mac/ProjectManager_Traits_Mac.h | 11 +++++++++++ .../Platform/Mac/ProjectManager_Traits_Platform.h | 11 +++++++++++ .../Platform/Windows/PAL_windows_files.cmake | 2 ++ .../Platform/Windows/ProjectManager_Traits_Platform.h | 11 +++++++++++ .../Platform/Windows/ProjectManager_Traits_Windows.h | 11 +++++++++++ Code/Tools/ProjectManager/Source/Application.cpp | 7 ++++++- 11 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h create mode 100644 Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h create mode 100644 Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h diff --git a/Code/Tools/ProjectManager/CMakeLists.txt b/Code/Tools/ProjectManager/CMakeLists.txt index d34abcbc6c..a47ccb62c9 100644 --- a/Code/Tools/ProjectManager/CMakeLists.txt +++ b/Code/Tools/ProjectManager/CMakeLists.txt @@ -34,6 +34,7 @@ ly_add_target( INCLUDE_DIRECTORIES PRIVATE Source + Platform/${PAL_PLATFORM_NAME} BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core diff --git a/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake b/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake index 11222602d5..c3acd44f9b 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake +++ b/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake @@ -11,4 +11,6 @@ set(FILES ProjectBuilderWorker_linux.cpp ProjectUtils_linux.cpp ProjectManagerDefs_linux.cpp + ProjectManager_Traits_Platform.h + ProjectManager_Traits_Linux.h ) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h new file mode 100644 index 0000000000..7c0543361f --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h @@ -0,0 +1,11 @@ +/* + * 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 + +#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h new file mode 100644 index 0000000000..97aee25507 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h @@ -0,0 +1,11 @@ +/* + * 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 + +#include diff --git a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake index 54b35f0d3c..6d4d453f21 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake +++ b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake @@ -11,4 +11,6 @@ set(FILES ProjectBuilderWorker_mac.cpp ProjectUtils_mac.cpp ProjectManagerDefs_mac.cpp + ProjectManager_Traits_Platform.h + ProjectManager_Traits_Mac.h ) diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h new file mode 100644 index 0000000000..7c0543361f --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h @@ -0,0 +1,11 @@ +/* + * 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 + +#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h new file mode 100644 index 0000000000..dc77e77fd0 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h @@ -0,0 +1,11 @@ +/* + * 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 + +#include diff --git a/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake b/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake index d95b0d2502..22b4614ddf 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake +++ b/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake @@ -11,4 +11,6 @@ set(FILES ProjectBuilderWorker_windows.cpp ProjectUtils_windows.cpp ProjectManagerDefs_windows.cpp + ProjectManager_Traits_Platform.h + ProjectManager_Traits_Windows.h ) diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h new file mode 100644 index 0000000000..f5eac50dbc --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h @@ -0,0 +1,11 @@ +/* + * 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 + +#include diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h new file mode 100644 index 0000000000..e6422b5a77 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h @@ -0,0 +1,11 @@ +/* + * 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 + +#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index a7e4805ce9..29e0df3c3a 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -194,8 +195,12 @@ namespace O3DE::ProjectManager // set stylesheet after creating the main window or their styles won't get updated AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:ProjectManager.qss")); - // the decoration wrapper is intended to remember window positioning and sizing + // the decoration wrapper is intended to remember window positioning and sizing +#if AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR auto wrapper = new AzQtComponents::WindowDecorationWrapper(); +#else + auto wrapper = new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionDisabled); +#endif wrapper->setGuest(m_mainWindow.data()); // show the main window here to apply the stylesheet before restoring geometry or we From a9fc376d6cabd0fd9006b0e4b7cf014ba1c01d14 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Mon, 25 Oct 2021 19:16:29 -0700 Subject: [PATCH 061/200] Upload AP logs when there is an AP eeror (#4896) * Updating LFS config to new endpoint (#1624) Signed-off-by: AMZN-alexpete * Updates licenses to APACHE-2.0 OR MIT (#1685) Not to be committed before 7/6/2021 Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> * Updating CONTRIBUTING.md Signed-off-by: Terry Michaels * Fixed typo Signed-off-by: Terry Michaels * Updated text to be more descriptive Signed-off-by: Terry Michaels * Upload AP logs when there is an AP eeror Signed-off-by: shiranj * Add AP log upload step for single step Asset jobs Signed-off-by: shiranj * Address more comments Signed-off-by: shiranj * Only call CreateUploadAPLogsStage() once in try/catch block Signed-off-by: shiranj * Revert acciental update to README.md Signed-off-by: shiranj Co-authored-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Co-authored-by: Chris Galvan Co-authored-by: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Co-authored-by: Terry Michaels Signed-off-by: Gene Walters --- scripts/build/Jenkins/Jenkinsfile | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 1388366661..f5e5edcf66 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -102,6 +102,10 @@ def IsJobEnabled(branchName, buildTypeMap, pipelineName, platformName) { } } +def IsAPLogUpload(branchName, jobName) { + return !IsPullRequest(branchName) && jobName.toLowerCase().contains('asset') && env.AP_LOGS_S3_BUCKET +} + def GetRunningPipelineName(JENKINS_JOB_NAME) { // If the job name has an underscore def job_parts = JENKINS_JOB_NAME.tokenize('/')[0].tokenize('_') @@ -431,6 +435,27 @@ def ExportTestScreenshots(Map options, String branchName, String platformName, S } } +def UploadAPLogs(Map options, String branchName, String jobName, String workspace, Map params) { + dir("${workspace}/${ENGINE_REPOSITORY_NAME}") { + projects = params.CMAKE_LY_PROJECTS.split(",") + projects.each{ project -> + def apLogsPath = "${project}/user/log" + def s3UploadScriptPath = "scripts/build/tools/upload_to_s3.py" + if(env.IS_UNIX) { + pythonPath = "${options.PYTHON_DIR}/python.sh" + } + else { + pythonPath = "${options.PYTHON_DIR}/python.cmd" + } + def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + + "--search_subdirectories True --key_prefix ${env.JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName}" + + "--extra-args {\"ACL\": \"bucket-owner-full-control\"}" + palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) + } + } + } + def PostBuildCommonSteps(String workspace, boolean mount = true) { echo 'Starting post-build common steps...' @@ -494,6 +519,14 @@ def CreateExportTestScreenshotsStage(Map pipelineConfig, String branchName, Stri } } +def CreateUploadAPLogsStage(Map pipelineConfig, String branchName, String jobName, String workspace, Map params) { + return { + stage("${jobName}_upload_ap_logs") { + UploadAPLogs(pipelineConfig, branchName, jobName, workspace, params) + } + } +} + def CreateTeardownStage(Map environmentVars) { return { stage('Teardown') { @@ -543,6 +576,9 @@ def CreateSingleNode(Map pipelineConfig, def platform, def build_job, Map envVar error "Node disconnected during build: ${e}" // Error raised to retry stage on a new node } } + if (IsAPLogUpload(branchName, build_job_name)) { + CreateUploadAPLogsStage(pipelineConfig, branchName, build_job_name, envVars['WORKSPACE'], platform.value.build_types[build_job_name].PARAMETERS).call() + } // All other errors will be raised outside the retry block currentResult = envVars['ON_FAILURE_MARK'] ?: 'FAILURE' currentException = e.toString() From 2e9ad896db30890c8563350ea3e301d37cfc503c Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Tue, 26 Oct 2021 01:59:02 -0700 Subject: [PATCH 062/200] Add some debug rendering options. (#4950) * [WIP] Adding rendering options Signed-off-by: rhhong * code review feedback. Also add the renderflag as qsettings. Signed-off-by: rhhong * fix broken test Signed-off-by: rhhong * fix linux build Signed-off-by: rhhong Signed-off-by: Gene Walters --- .../EMotionFXAtom/Assets/Icons/Resources.qrc | 1 + .../Assets/Icons/Visualization.svg | 9 + .../Code/Source/AtomActorDebugDraw.cpp | 415 ++++++++++++++++++ .../Code/Source/AtomActorDebugDraw.h | 56 +++ .../Code/Source/AtomActorInstance.cpp | 118 +---- .../Code/Source/AtomActorInstance.h | 11 +- .../Tools/EMStudio/AnimViewportRenderer.cpp | 14 + .../Tools/EMStudio/AnimViewportRenderer.h | 6 +- .../Tools/EMStudio/AnimViewportRequestBus.h | 5 +- .../Tools/EMStudio/AnimViewportToolBar.cpp | 112 ++++- .../Code/Tools/EMStudio/AnimViewportToolBar.h | 11 + .../Tools/EMStudio/AnimViewportWidget.cpp | 46 +- .../Code/Tools/EMStudio/AnimViewportWidget.h | 8 + .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 8 +- .../Code/emotionfx_atom_files.cmake | 2 + .../Include/Integration/ActorComponentBus.h | 3 - .../Integration/Components/ActorComponent.cpp | 31 +- .../Integration/Components/ActorComponent.h | 5 +- .../Components/EditorActorComponent.cpp | 15 +- .../Editor/Components/EditorActorComponent.h | 3 + .../Rendering/RenderActorInstance.h | 12 +- .../Source/Integration/Rendering/RenderFlag.h | 44 ++ .../Code/Tests/RenderBackendManagerTests.cpp | 3 +- 23 files changed, 751 insertions(+), 187 deletions(-) create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Visualization.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h create mode 100644 Gems/EMotionFX/Code/Source/Integration/Rendering/RenderFlag.h diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc index 28ae322d5b..7924ef1c4e 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc @@ -1,5 +1,6 @@ Camera_category.svg + Visualization.svg diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Visualization.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Visualization.svg new file mode 100644 index 0000000000..3d1b40d1b6 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Visualization.svg @@ -0,0 +1,9 @@ + + + + Icons / System / View + Created with Sketch. + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp new file mode 100644 index 0000000000..eaaf04fcf2 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp @@ -0,0 +1,415 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include + +namespace AZ::Render +{ + AtomActorDebugDraw::AtomActorDebugDraw(AZ::EntityId entityId) + { + m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(entityId); + } + + void AtomActorDebugDraw::DebugDraw(const EMotionFX::ActorRenderFlagBitset& renderFlags, EMotionFX::ActorInstance* instance) + { + if (!m_auxGeomFeatureProcessor || !instance) + { + return; + } + + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + if (!auxGeom) + { + return; + } + + // Render aabb + if (renderFlags[EMotionFX::ActorRenderFlag::RENDER_AABB]) + { + RenderAABB(instance); + } + + // Render skeleton + if (renderFlags[EMotionFX::ActorRenderFlag::RENDER_LINESKELETON]) + { + RenderSkeleton(instance); + } + + // Render internal EMFX debug lines. + if (renderFlags[EMotionFX::ActorRenderFlag::RENDER_EMFX_DEBUG]) + { + RenderEMFXDebugDraw(instance); + } + + // Render vertex normal, face normal, tagent and wireframe. + const bool renderVertexNormals = renderFlags[EMotionFX::ActorRenderFlag::RENDER_VERTEXNORMALS]; + const bool renderFaceNormals = renderFlags[EMotionFX::ActorRenderFlag::RENDER_FACENORMALS]; + const bool renderTangents = renderFlags[EMotionFX::ActorRenderFlag::RENDER_TANGENTS]; + const bool renderWireframe = renderFlags[EMotionFX::ActorRenderFlag::RENDER_WIREFRAME]; + + if (renderVertexNormals || renderFaceNormals || renderTangents || renderWireframe) + { + // Iterate through all enabled nodes + const EMotionFX::Pose* pose = instance->GetTransformData()->GetCurrentPose(); + const size_t geomLODLevel = instance->GetLODLevel(); + const size_t numEnabled = instance->GetNumEnabledNodes(); + for (size_t i = 0; i < numEnabled; ++i) + { + EMotionFX::Node* node = instance->GetActor()->GetSkeleton()->GetNode(instance->GetEnabledNode(i)); + EMotionFX::Mesh* mesh = instance->GetActor()->GetMesh(geomLODLevel, node->GetNodeIndex()); + const AZ::Transform globalTM = pose->GetWorldSpaceTransform(node->GetNodeIndex()).ToAZTransform(); + + m_currentMesh = nullptr; + + if (!mesh) + { + continue; + } + + RenderNormals(mesh, globalTM, renderVertexNormals, renderFaceNormals); + if (renderTangents) + { + RenderTangents(mesh, globalTM); + } + } + } + } + + void AtomActorDebugDraw::PrepareForMesh(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) + { + // Check if we have already prepared for the given mesh + if (m_currentMesh == mesh) + { + return; + } + + // Set our new current mesh + m_currentMesh = mesh; + + // Get the number of vertices and the data + const uint32 numVertices = m_currentMesh->GetNumVertices(); + AZ::Vector3* positions = (AZ::Vector3*)m_currentMesh->FindVertexData(EMotionFX::Mesh::ATTRIB_POSITIONS); + + // Check if the vertices fits in our buffer + if (m_worldSpacePositions.size() < numVertices) + { + m_worldSpacePositions.resize(numVertices); + } + + // Pre-calculate the world space positions + for (uint32 i = 0; i < numVertices; ++i) + { + m_worldSpacePositions[i] = worldTM.TransformPoint(positions[i]); + } + } + + void AtomActorDebugDraw::RenderAABB(EMotionFX::ActorInstance* instance) + { + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + const AZ::Aabb& aabb = instance->GetAabb(); + auxGeom->DrawAabb(aabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); + } + + void AtomActorDebugDraw::RenderSkeleton(EMotionFX::ActorInstance* instance) + { + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + + const EMotionFX::TransformData* transformData = instance->GetTransformData(); + const EMotionFX::Skeleton* skeleton = instance->GetActor()->GetSkeleton(); + const EMotionFX::Pose* pose = transformData->GetCurrentPose(); + + const size_t lodLevel = instance->GetLODLevel(); + const size_t numJoints = skeleton->GetNumNodes(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numJoints * 2); + + for (size_t jointIndex = 0; jointIndex < numJoints; ++jointIndex) + { + const EMotionFX::Node* joint = skeleton->GetNode(jointIndex); + if (!joint->GetSkeletalLODStatus(lodLevel)) + { + continue; + } + + const size_t parentIndex = joint->GetParentIndex(); + if (parentIndex == InvalidIndex) + { + continue; + } + + const AZ::Vector3 parentPos = pose->GetWorldSpaceTransform(parentIndex).m_position; + m_auxVertices.emplace_back(parentPos); + + const AZ::Vector3 bonePos = pose->GetWorldSpaceTransform(jointIndex).m_position; + m_auxVertices.emplace_back(bonePos); + } + + const AZ::Color skeletonColor(0.604f, 0.804f, 0.196f, 1.0f); + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = &skeletonColor; + lineArgs.m_colorCount = 1; + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + void AtomActorDebugDraw::RenderEMFXDebugDraw(EMotionFX::ActorInstance* instance) + { + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + + EMotionFX::DebugDraw& debugDraw = EMotionFX::GetDebugDraw(); + debugDraw.Lock(); + EMotionFX::DebugDraw::ActorInstanceData* actorInstanceData = debugDraw.GetActorInstanceData(instance); + actorInstanceData->Lock(); + const AZStd::vector& lines = actorInstanceData->GetLines(); + if (lines.empty()) + { + actorInstanceData->Unlock(); + debugDraw.Unlock(); + return; + } + + m_auxVertices.clear(); + m_auxVertices.reserve(lines.size() * 2); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + for (const EMotionFX::DebugDraw::Line& line : actorInstanceData->GetLines()) + { + m_auxVertices.emplace_back(line.m_start); + m_auxColors.emplace_back(line.m_startColor); + m_auxVertices.emplace_back(line.m_end); + m_auxColors.emplace_back(line.m_endColor); + } + + AZ_Assert(m_auxVertices.size() == m_auxColors.size(), "Number of vertices and number of colors need to match."); + actorInstanceData->Unlock(); + debugDraw.Unlock(); + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + void AtomActorDebugDraw::RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals) + { + if (!mesh) + { + return; + } + + if (!vertexNormals && !faceNormals) + { + return; + } + + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + if (!auxGeom) + { + return; + } + + // TODO: Move line color to a render setting. + const float faceNormalsScale = 0.01f; + const AZ::Color colorFaceNormals = AZ::Colors::Lime; + const float vertexNormalsScale = 0.01f; + const AZ::Color colorVertexNormals = AZ::Colors::Orange; + + PrepareForMesh(mesh, worldTM); + + AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); + + // Render face normals + if (faceNormals) + { + const size_t numSubMeshes = mesh->GetNumSubMeshes(); + for (uint32 subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex) + { + EMotionFX::SubMesh* subMesh = mesh->GetSubMesh(subMeshIndex); + const uint32 numTriangles = subMesh->GetNumPolygons(); + const uint32 startVertex = subMesh->GetStartVertex(); + const uint32* indices = subMesh->GetIndices(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numTriangles * 2); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + for (uint32 triangleIndex = 0; triangleIndex < numTriangles; ++triangleIndex) + { + const uint32 triangleStartIndex = triangleIndex * 3; + const uint32 indexA = indices[triangleStartIndex + 0] + startVertex; + const uint32 indexB = indices[triangleStartIndex + 1] + startVertex; + const uint32 indexC = indices[triangleStartIndex + 2] + startVertex; + + const AZ::Vector3& posA = m_worldSpacePositions[indexA]; + const AZ::Vector3& posB = m_worldSpacePositions[indexB]; + const AZ::Vector3& posC = m_worldSpacePositions[indexC]; + + const AZ::Vector3 normalDir = (posB - posA).Cross(posC - posA).GetNormalized(); + + // Calculate the center pos + const AZ::Vector3 normalPos = (posA + posB + posC) * (1.0f / 3.0f); + + m_auxVertices.emplace_back(normalPos); + m_auxColors.emplace_back(colorFaceNormals); + m_auxVertices.emplace_back(normalPos + (normalDir * faceNormalsScale)); + m_auxColors.emplace_back(colorFaceNormals); + } + } + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + + // render vertex normals + if (vertexNormals) + { + const size_t numSubMeshes = mesh->GetNumSubMeshes(); + for (uint32 subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex) + { + EMotionFX::SubMesh* subMesh = mesh->GetSubMesh(subMeshIndex); + const uint32 numVertices = subMesh->GetNumVertices(); + const uint32 startVertex = subMesh->GetStartVertex(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numVertices * 2); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + for (uint32 j = 0; j < numVertices; ++j) + { + const uint32 vertexIndex = j + startVertex; + const AZ::Vector3& position = m_worldSpacePositions[vertexIndex]; + const AZ::Vector3 normal = worldTM.TransformVector(normals[vertexIndex]).GetNormalizedSafe() * vertexNormalsScale; + + m_auxVertices.emplace_back(position); + m_auxColors.emplace_back(colorFaceNormals); + m_auxVertices.emplace_back(position + normal); + m_auxColors.emplace_back(colorFaceNormals); + } + } + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } + } + + void AtomActorDebugDraw::RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) + { + if (!mesh) + { + return; + } + + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + if (!auxGeom) + { + return; + } + + // TODO: Move line color to a render setting. + const AZ::Color colorTangents = AZ::Colors::Red; + const AZ::Color mirroredBitangentColor = AZ::Colors::Yellow; + const AZ::Color colorBitangents = AZ::Colors::White; + const float scale = 0.01f; + + // Get the tangents and check if this mesh actually has tangents + AZ::Vector4* tangents = static_cast(mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_TANGENTS)); + if (!tangents) + { + return; + } + + AZ::Vector3* bitangents = static_cast(mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_BITANGENTS)); + + PrepareForMesh(mesh, worldTM); + + AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); + const uint32 numVertices = mesh->GetNumVertices(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numVertices * 2); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + // Render the tangents and bitangents + AZ::Vector3 orgTangent, tangent, bitangent; + for (uint32 i = 0; i < numVertices; ++i) + { + orgTangent.Set(tangents[i].GetX(), tangents[i].GetY(), tangents[i].GetZ()); + tangent = (worldTM.TransformVector(orgTangent)).GetNormalized(); + + if (bitangents) + { + bitangent = bitangents[i]; + } + else + { + bitangent = tangents[i].GetW() * normals[i].Cross(orgTangent); + } + bitangent = (worldTM.TransformVector(bitangent)).GetNormalizedSafe(); + + m_auxVertices.emplace_back(m_worldSpacePositions[i]); + m_auxColors.emplace_back(colorTangents); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (tangent * scale)); + m_auxColors.emplace_back(colorTangents); + + if (tangents[i].GetW() < 0.0f) + { + m_auxVertices.emplace_back(m_worldSpacePositions[i]); + m_auxColors.emplace_back(mirroredBitangentColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * scale)); + m_auxColors.emplace_back(mirroredBitangentColor); + } + else + { + m_auxVertices.emplace_back(m_worldSpacePositions[i]); + m_auxColors.emplace_back(colorBitangents); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * scale)); + m_auxColors.emplace_back(colorBitangents); + } + } + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } +} // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h new file mode 100644 index 0000000000..9f8b137f13 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h @@ -0,0 +1,56 @@ +/* + * 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 + +#include +#include +#include +#include + +namespace EMotionFX +{ + class Mesh; + class ActorInstance; +} + +namespace AZ::RPI +{ + class AuxGeomDraw; + class AuxGeomFeatureProcessorInterface; +} + +namespace AZ::Render +{ + // Ultility class for atom debug render on actor + class AtomActorDebugDraw + { + public: + AtomActorDebugDraw(AZ::EntityId entityId); + + void DebugDraw(const EMotionFX::ActorRenderFlagBitset& renderFlags, EMotionFX::ActorInstance* instance); + + private: + + void PrepareForMesh(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); + void RenderAABB(EMotionFX::ActorInstance* instance); + void RenderSkeleton(EMotionFX::ActorInstance* instance); + void RenderEMFXDebugDraw(EMotionFX::ActorInstance* instance); + void RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals); + void RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); + + EMotionFX::Mesh* m_currentMesh = nullptr; /**< A pointer to the mesh whose world space positions are in the pre-calculated positions buffer. + NULL in case we haven't pre-calculated any positions yet. */ + AZStd::vector m_worldSpacePositions; /**< The buffer used to store world space positions for rendering normals + tangents and the wireframe. */ + + RPI::AuxGeomFeatureProcessorInterface* m_auxGeomFeatureProcessor = nullptr; + AZStd::vector m_auxVertices; + AZStd::vector m_auxColors; + }; +} diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index a3161002a0..4d1b42a0eb 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -59,7 +60,7 @@ namespace AZ AzFramework::BoundsRequestBus::Handler::BusConnect(m_entityId); } - m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(m_entityId); + m_atomActorDebugDraw = AZStd::make_unique(entityId); } AtomActorInstance::~AtomActorInstance() @@ -78,6 +79,11 @@ namespace AZ UpdateBounds(); } + void AtomActorInstance::DebugDraw(const EMotionFX::ActorRenderFlagBitset& renderFlags) + { + m_atomActorDebugDraw->DebugDraw(renderFlags, m_actorInstance); + } + void AtomActorInstance::UpdateBounds() { // Update RenderActorInstance world bounding box @@ -99,116 +105,6 @@ namespace AZ AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); } - void AtomActorInstance::DebugDraw(const DebugOptions& debugOptions) - { - if (m_auxGeomFeatureProcessor) - { - if (RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue()) - { - if (debugOptions.m_drawAABB) - { - const AZ::Aabb& aabb = m_actorInstance->GetAabb(); - auxGeom->DrawAabb(aabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); - } - - if (debugOptions.m_drawSkeleton) - { - RenderSkeleton(auxGeom.get()); - } - - if (debugOptions.m_emfxDebugDraw) - { - RenderEMFXDebugDraw(auxGeom.get()); - } - } - } - } - - void AtomActorInstance::RenderSkeleton(RPI::AuxGeomDraw* auxGeom) - { - AZ_Assert(m_actorInstance, "Valid actor instance required."); - const EMotionFX::TransformData* transformData = m_actorInstance->GetTransformData(); - const EMotionFX::Skeleton* skeleton = m_actorInstance->GetActor()->GetSkeleton(); - const EMotionFX::Pose* pose = transformData->GetCurrentPose(); - - const size_t lodLevel = m_actorInstance->GetLODLevel(); - const size_t numJoints = skeleton->GetNumNodes(); - - m_auxVertices.clear(); - m_auxVertices.reserve(numJoints * 2); - - for (size_t jointIndex = 0; jointIndex < numJoints; ++jointIndex) - { - const EMotionFX::Node* joint = skeleton->GetNode(jointIndex); - if (!joint->GetSkeletalLODStatus(lodLevel)) - { - continue; - } - - const size_t parentIndex = joint->GetParentIndex(); - if (parentIndex == InvalidIndex) - { - continue; - } - - const AZ::Vector3 parentPos = pose->GetWorldSpaceTransform(parentIndex).m_position; - m_auxVertices.emplace_back(parentPos); - - const AZ::Vector3 bonePos = pose->GetWorldSpaceTransform(jointIndex).m_position; - m_auxVertices.emplace_back(bonePos); - } - - const AZ::Color skeletonColor(0.604f, 0.804f, 0.196f, 1.0f); - RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; - lineArgs.m_verts = m_auxVertices.data(); - lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &skeletonColor; - lineArgs.m_colorCount = 1; - lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; - auxGeom->DrawLines(lineArgs); - } - - void AtomActorInstance::RenderEMFXDebugDraw(RPI::AuxGeomDraw* auxGeom) - { - EMotionFX::DebugDraw& debugDraw = EMotionFX::GetDebugDraw(); - debugDraw.Lock(); - EMotionFX::DebugDraw::ActorInstanceData* actorInstanceData = debugDraw.GetActorInstanceData(m_actorInstance); - actorInstanceData->Lock(); - const AZStd::vector& lines = actorInstanceData->GetLines(); - if (lines.empty()) - { - actorInstanceData->Unlock(); - debugDraw.Unlock(); - return; - } - - m_auxVertices.clear(); - m_auxVertices.reserve(lines.size() * 2); - m_auxColors.clear(); - m_auxColors.reserve(m_auxVertices.size()); - - for (const EMotionFX::DebugDraw::Line& line : actorInstanceData->GetLines()) - { - m_auxVertices.emplace_back(line.m_start); - m_auxColors.emplace_back(line.m_startColor); - m_auxVertices.emplace_back(line.m_end); - m_auxColors.emplace_back(line.m_endColor); - } - - AZ_Assert(m_auxVertices.size() == m_auxColors.size(), - "Number of vertices and number of colors need to match."); - actorInstanceData->Unlock(); - debugDraw.Unlock(); - - RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; - lineArgs.m_verts = m_auxVertices.data(); - lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = m_auxColors.data(); - lineArgs.m_colorCount = static_cast(m_auxColors.size()); - lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; - auxGeom->DrawLines(lineArgs); - } - AZ::Aabb AtomActorInstance::GetWorldBounds() { return m_worldAABB; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h index 5ddab8bc61..7f646466a5 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.h @@ -53,6 +53,7 @@ namespace AZ class SkinnedMeshInputBuffers; class MeshFeatureProcessorInterface; class AtomActor; + class AtomActorDebugDraw; //! Render node for managing and rendering actor instances. Each Actor Component //! creates an ActorRenderNode. The render node is responsible for drawing meshes and @@ -85,8 +86,8 @@ namespace AZ // RenderActorInstance overrides ... void OnTick(float timeDelta) override; + void DebugDraw(const EMotionFX::ActorRenderFlagBitset& renderFlags); void UpdateBounds() override; - void DebugDraw(const DebugOptions& debugOptions) override; void SetMaterials(const EMotionFX::Integration::ActorAsset::MaterialList& materialPerLOD) override { AZ_UNUSED(materialPerLOD); }; void SetSkinningMethod(EMotionFX::Integration::SkinningMethod emfxSkinningMethod) override; SkinningMethod GetAtomSkinningMethod() const; @@ -184,12 +185,8 @@ namespace AZ void InitWrinkleMasks(); void UpdateWrinkleMasks(); - // Helper and debug geometry rendering - void RenderSkeleton(RPI::AuxGeomDraw* auxGeom); - void RenderEMFXDebugDraw(RPI::AuxGeomDraw* auxGeom); - RPI::AuxGeomFeatureProcessorInterface* m_auxGeomFeatureProcessor = nullptr; - AZStd::vector m_auxVertices; - AZStd::vector m_auxColors; + // Debug geometry rendering + AZStd::unique_ptr m_atomActorDebugDraw; AZStd::intrusive_ptr m_skinnedMeshInputBuffers = nullptr; AZStd::intrusive_ptr m_skinnedMeshInstance; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index faa033956a..f6186be235 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -206,6 +206,20 @@ namespace EMStudio return result; } + void AnimViewportRenderer::UpdateActorRenderFlag(EMotionFX::ActorRenderFlagBitset renderFlags) + { + for (AZ::Entity* entity : m_actorEntities) + { + EMotionFX::Integration::ActorComponent* actorComponent = entity->FindComponent(); + if (!actorComponent) + { + AZ_Assert(false, "Found entity without actor component in the actor entity list."); + continue; + } + actorComponent->SetRenderFlag(renderFlags); + } + } + void AnimViewportRenderer::ResetEnvironment() { // Reset environment diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index 1de4cbdb1c..a4f67ddfd1 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -52,6 +52,8 @@ namespace EMStudio //! Return the center position of the existing objects. AZ::Vector3 GetCharacterCenter() const; + void UpdateActorRenderFlag(EMotionFX::ActorRenderFlagBitset renderFlags); + private: // This function resets the light, camera and other environment settings. @@ -79,10 +81,6 @@ namespace EMStudio AZ::Entity* m_postProcessEntity = nullptr; AZ::Entity* m_iblEntity = nullptr; - AZ::Entity* m_cameraEntity = nullptr; - AZ::Component* m_cameraComponent = nullptr; - AZ::Entity* m_modelEntity = nullptr; - AZ::Data::AssetId m_modelAssetId; AZ::Entity* m_gridEntity = nullptr; AZStd::vector m_actorEntities; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h index 03784c2158..da4a054c53 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h @@ -8,7 +8,7 @@ #pragma once #include - +#include namespace EMStudio { @@ -35,6 +35,9 @@ namespace EMStudio //! Set the camera view mode. virtual void SetCameraViewMode(CameraViewMode mode) = 0; + + //! Toggle render option flag + virtual void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) = 0; }; using AnimViewportRequestBus = AZ::EBus; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp index a47a773e10..50cd088f5d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp @@ -13,7 +13,6 @@ #include #include - namespace EMStudio { AnimViewportToolBar::AnimViewportToolBar(QWidget* parent) @@ -21,40 +20,107 @@ namespace EMStudio { AzQtComponents::ToolBar::addMainToolBarStyle(this); + // Add the render view options button + QToolButton* renderOptionsButton = new QToolButton(this); + { + QMenu* contextMenu = new QMenu(renderOptionsButton); + + renderOptionsButton->setText("Render Options"); + renderOptionsButton->setMenu(contextMenu); + renderOptionsButton->setPopupMode(QToolButton::InstantPopup); + renderOptionsButton->setVisible(true); + renderOptionsButton->setIcon(QIcon(":/EMotionFXAtom/Visualization.svg")); + addWidget(renderOptionsButton); + + CreateViewOptionEntry(contextMenu, "Solid", EMotionFX::ActorRenderFlag::RENDER_SOLID); + CreateViewOptionEntry(contextMenu, "Wireframe", EMotionFX::ActorRenderFlag::RENDER_WIREFRAME); + CreateViewOptionEntry(contextMenu, "Lighting", EMotionFX::ActorRenderFlag::RENDER_LIGHTING); + CreateViewOptionEntry(contextMenu, "Backface Culling", EMotionFX::ActorRenderFlag::RENDER_BACKFACECULLING); + contextMenu->addSeparator(); + CreateViewOptionEntry(contextMenu, "Vertex Normals", EMotionFX::ActorRenderFlag::RENDER_VERTEXNORMALS); + CreateViewOptionEntry(contextMenu, "Face Normals", EMotionFX::ActorRenderFlag::RENDER_FACENORMALS); + CreateViewOptionEntry(contextMenu, "Tangents", EMotionFX::ActorRenderFlag::RENDER_TANGENTS); + CreateViewOptionEntry(contextMenu, "Actor Bounding Boxes", EMotionFX::ActorRenderFlag::RENDER_AABB); + contextMenu->addSeparator(); + CreateViewOptionEntry(contextMenu, "Line Skeleton", EMotionFX::ActorRenderFlag::RENDER_LINESKELETON); + CreateViewOptionEntry(contextMenu, "Solid Skeleton", EMotionFX::ActorRenderFlag::RENDER_SKELETON); + CreateViewOptionEntry(contextMenu, "Joint Names", EMotionFX::ActorRenderFlag::RENDER_NODENAMES); + CreateViewOptionEntry(contextMenu, "Joint Orientations", EMotionFX::ActorRenderFlag::RENDER_NODEORIENTATION); + CreateViewOptionEntry(contextMenu, "Actor Bind Pose", EMotionFX::ActorRenderFlag::RENDER_ACTORBINDPOSE); + contextMenu->addSeparator(); + } + // Add the camera button QToolButton* cameraButton = new QToolButton(this); - QMenu* cameraMenu = new QMenu(cameraButton); + { + QMenu* cameraMenu = new QMenu(cameraButton); - // Add the camera option - const AZStd::vector> cameraOptionNames = { - { CameraViewMode::FRONT, "Front" }, { CameraViewMode::BACK, "Back" }, { CameraViewMode::TOP, "Top" }, - { CameraViewMode::BOTTOM, "Bottom" }, { CameraViewMode::LEFT, "Left" }, { CameraViewMode::RIGHT, "Right" }, - }; + // Add the camera option + const AZStd::vector> cameraOptionNames = { + { CameraViewMode::FRONT, "Front" }, { CameraViewMode::BACK, "Back" }, { CameraViewMode::TOP, "Top" }, + { CameraViewMode::BOTTOM, "Bottom" }, { CameraViewMode::LEFT, "Left" }, { CameraViewMode::RIGHT, "Right" }, + }; - for (const auto& pair : cameraOptionNames) - { - CameraViewMode mode = pair.first; + for (const auto& pair : cameraOptionNames) + { + CameraViewMode mode = pair.first; + cameraMenu->addAction( + pair.second.c_str(), + [mode]() + { + // Send the reset camera event. + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::SetCameraViewMode, mode); + }); + } + + cameraMenu->addSeparator(); cameraMenu->addAction( - pair.second.c_str(), - [mode]() + "Reset Camera", + []() { // Send the reset camera event. - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::SetCameraViewMode, mode); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::ResetCamera); }); + cameraButton->setMenu(cameraMenu); + cameraButton->setText("Camera Option"); + cameraButton->setPopupMode(QToolButton::InstantPopup); + cameraButton->setVisible(true); + cameraButton->setIcon(QIcon(":/EMotionFXAtom/Camera_category.svg")); + addWidget(cameraButton); } + } - cameraMenu->addSeparator(); - cameraMenu->addAction("Reset Camera", - []() + void AnimViewportToolBar::CreateViewOptionEntry( + QMenu* menu, const char* menuEntryName, uint32_t actionIndex, bool visible, char* iconFileName) + { + QAction* action = menu->addAction( + menuEntryName, + [actionIndex]() { // Send the reset camera event. - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::ResetCamera); + AnimViewportRequestBus::Broadcast( + &AnimViewportRequestBus::Events::ToggleRenderFlag, (EMotionFX::ActorRenderFlag)actionIndex); }); - cameraButton->setMenu(cameraMenu); - cameraButton->setText("Camera Option"); - cameraButton->setPopupMode(QToolButton::InstantPopup); - cameraButton->setVisible(true); - cameraButton->setIcon(QIcon(":/EMotionFXAtom/Camera_category.svg")); - addWidget(cameraButton); + action->setCheckable(true); + action->setVisible(visible); + + if (iconFileName) + { + action->setIcon(QIcon(iconFileName)); + } + + m_actions[actionIndex] = action; + } + + void AnimViewportToolBar::SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) + { + for (size_t i = 0; i < renderFlags.size(); ++i) + { + QAction* action = m_actions[i]; + if (action) + { + action->setChecked(renderFlags[i]); + } + } } } // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h index 23ef5fdcd8..57633e5284 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h @@ -11,8 +11,11 @@ #if !defined(Q_MOC_RUN) #include #include +#include #endif +#include + namespace EMStudio { class AnimViewportToolBar : public QToolBar @@ -20,5 +23,13 @@ namespace EMStudio public: AnimViewportToolBar(QWidget* parent = nullptr); ~AnimViewportToolBar() = default; + + void SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); + + private: + void CreateViewOptionEntry( + QMenu* menu, const char* menuEntryName, uint32_t actionIndex, bool visible = true, char* iconFileName = nullptr); + + QAction* m_actions[EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS] = { nullptr }; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 2e05864adc..7af5c1607a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ namespace EMStudio m_renderer = AZStd::make_unique(GetViewportContext()); + LoadRenderFlags(); SetupCameras(); SetupCameraController(); Reinit(); @@ -41,6 +43,7 @@ namespace EMStudio AnimViewportWidget::~AnimViewportWidget() { + SaveRenderFlags(); AnimViewportRequestBus::Handler::BusDisconnect(); } @@ -50,7 +53,14 @@ namespace EMStudio { ResetCamera(); } + m_renderer->Reinit(); + m_renderer->UpdateActorRenderFlag(m_renderFlags); + } + + EMotionFX::ActorRenderFlagBitset AnimViewportWidget::GetRenderFlags() const + { + return m_renderFlags; } void AnimViewportWidget::SetupCameras() @@ -123,7 +133,7 @@ namespace EMStudio SetCameraViewMode(CameraViewMode::DEFAULT); } - void AnimViewportWidget::SetCameraViewMode([[maybe_unused]]CameraViewMode mode) + void AnimViewportWidget::SetCameraViewMode(CameraViewMode mode) { // Set the camera view mode. const AZ::Vector3 targetPosition = m_renderer->GetCharacterCenter(); @@ -155,4 +165,38 @@ namespace EMStudio } GetViewportContext()->SetCameraTransform(AZ::Transform::CreateLookAt(cameraPosition, targetPosition)); } + + void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) + { + m_renderFlags[flag] = !m_renderFlags[flag]; + m_renderer->UpdateActorRenderFlag(m_renderFlags); + } + + void AnimViewportWidget::LoadRenderFlags() + { + AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); + renderFlagsFilename += "AnimViewportRenderFlags.cfg"; + QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); + + for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) + { + QString name = QString(i); + const bool isEnabled = settings.value(name).toBool(); + m_renderFlags[i] = isEnabled; + } + m_renderer->UpdateActorRenderFlag(m_renderFlags); + } + + void AnimViewportWidget::SaveRenderFlags() + { + AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); + renderFlagsFilename += "AnimViewportRenderFlags.cfg"; + QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); + + for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) + { + QString name = QString(i); + settings.setValue(name, (bool)m_renderFlags[i]); + } + } } // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 6d708b0996..8aa316a8ba 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -7,9 +7,11 @@ */ #pragma once +#include #include #include #include +#include namespace EMStudio { @@ -25,14 +27,19 @@ namespace EMStudio AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); } void Reinit(bool resetCamera = true); + EMotionFX::ActorRenderFlagBitset GetRenderFlags() const; private: void SetupCameras(); void SetupCameraController(); + void LoadRenderFlags(); + void SaveRenderFlags(); + // AnimViewportRequestBus::Handler overrides void ResetCamera(); void SetCameraViewMode(CameraViewMode mode); + void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag); static constexpr float CameraDistance = 2.0f; @@ -40,5 +47,6 @@ namespace EMStudio AZStd::shared_ptr m_rotateCamera; AZStd::shared_ptr m_translateCamera; AZStd::shared_ptr m_orbitDollyScrollCamera; + EMotionFX::ActorRenderFlagBitset m_renderFlags; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index bc74592485..ce2e76a6c7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -90,12 +90,14 @@ namespace EMStudio verticalLayout->setSpacing(1); verticalLayout->setMargin(0); + // Add the viewport widget + m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + // Add the tool bar AnimViewportToolBar* toolBar = new AnimViewportToolBar(m_innerWidget); - verticalLayout->addWidget(toolBar); + toolBar->SetRenderFlags(m_animViewportWidget->GetRenderFlags()); - // Add the viewport widget - m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + verticalLayout->addWidget(toolBar); verticalLayout->addWidget(m_animViewportWidget); // Register command callbacks. diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_files.cmake b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_files.cmake index 4ada953caf..413984b96d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_files.cmake +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_files.cmake @@ -17,4 +17,6 @@ set(FILES Source/AtomActor.cpp Source/AtomActorInstance.h Source/AtomActorInstance.cpp + Source/AtomActorDebugDraw.h + Source/AtomActorDebugDraw.cpp ) diff --git a/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h b/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h index 4161b3c77d..1fd3e55f12 100644 --- a/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h +++ b/Gems/EMotionFX/Code/Include/Integration/ActorComponentBus.h @@ -85,9 +85,6 @@ namespace EMotionFX /// Detach from parent entity, if attached. virtual void DetachFromEntity() {} - /// Enables debug-drawing of the actor's root. - virtual void DebugDrawRoot(bool /*enable*/) {} - /// Enables rendering of the actor. virtual bool GetRenderCharacter() const = 0; virtual void SetRenderCharacter(bool enable) = 0; diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp index 206cae3f59..8520896dd2 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.cpp @@ -209,7 +209,6 @@ namespace EMotionFX ->Event("GetJointTransform", &ActorComponentRequestBus::Events::GetJointTransform) ->Event("AttachToEntity", &ActorComponentRequestBus::Events::AttachToEntity) ->Event("DetachFromEntity", &ActorComponentRequestBus::Events::DetachFromEntity) - ->Event("DebugDrawRoot", &ActorComponentRequestBus::Events::DebugDrawRoot) ->Event("GetRenderCharacter", &ActorComponentRequestBus::Events::GetRenderCharacter) ->Event("SetRenderCharacter", &ActorComponentRequestBus::Events::SetRenderCharacter) ->Event("GetRenderActorVisible", &ActorComponentRequestBus::Events::GetRenderActorVisible) @@ -238,8 +237,7 @@ namespace EMotionFX ////////////////////////////////////////////////////////////////////////// ActorComponent::ActorComponent(const Configuration* configuration) - : m_debugDrawRoot(false) - , m_sceneFinishSimHandler([this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle, + : m_sceneFinishSimHandler([this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle, float fixedDeltatime) { if (m_actorInstance) @@ -252,6 +250,8 @@ namespace EMotionFX { m_configuration = *configuration; } + + m_debugRenderFlags[RENDER_SOLID] = true; } ////////////////////////////////////////////////////////////////////////// @@ -341,12 +341,6 @@ namespace EMotionFX } } - ////////////////////////////////////////////////////////////////////////// - void ActorComponent::DebugDrawRoot(bool enable) - { - m_debugDrawRoot = enable; - } - ////////////////////////////////////////////////////////////////////////// bool ActorComponent::GetRenderCharacter() const { @@ -400,6 +394,11 @@ namespace EMotionFX return m_sceneFinishSimHandler.IsConnected(); } + void ActorComponent::SetRenderFlag(ActorRenderFlagBitset renderFlags) + { + m_debugRenderFlags = renderFlags; + } + void ActorComponent::CheckActorCreation() { // Create actor instance. @@ -573,13 +572,13 @@ namespace EMotionFX m_actorInstance->SetIsVisible(isInCameraFrustum && m_configuration.m_renderCharacter); } - RenderActorInstance::DebugOptions debugOptions; - debugOptions.m_drawAABB = m_configuration.m_renderBounds; - debugOptions.m_drawSkeleton = m_configuration.m_renderSkeleton; - debugOptions.m_drawRootTransform = m_debugDrawRoot; - debugOptions.m_rootWorldTransform = GetEntity()->GetTransform()->GetWorldTM(); - debugOptions.m_emfxDebugDraw = true; - m_renderActorInstance->DebugDraw(debugOptions); + m_renderActorInstance->SetIsVisible(m_debugRenderFlags[RENDER_SOLID]); + + // The configuration stores some debug option. When that is enabled, we override it on top of the render flags. + m_debugRenderFlags[RENDER_AABB] = m_debugRenderFlags[RENDER_AABB] || m_configuration.m_renderBounds; + m_debugRenderFlags[RENDER_SKELETON] = m_debugRenderFlags[RENDER_SKELETON] || m_configuration.m_renderSkeleton; + m_debugRenderFlags[RENDER_EMFX_DEBUG] = true; + m_renderActorInstance->DebugDraw(m_debugRenderFlags); } } diff --git a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h index 15d9736f34..9eecea2f54 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Components/ActorComponent.h @@ -116,7 +116,6 @@ namespace EMotionFX ActorInstance* GetActorInstance() override { return m_actorInstance.get(); } void AttachToEntity(AZ::EntityId targetEntityId, AttachmentType attachmentType) override; void DetachFromEntity() override; - void DebugDrawRoot(bool enable) override; bool GetRenderCharacter() const override; void SetRenderCharacter(bool enable) override; bool GetRenderActorVisible() const override; @@ -181,6 +180,8 @@ namespace EMotionFX bool IsPhysicsSceneSimulationFinishEventConnected() const; AZ::Data::Asset GetActorAsset() const { return m_configuration.m_actorAsset; } + void SetRenderFlag(ActorRenderFlagBitset renderFlags); + private: // AZ::TransformNotificationBus::MultiHandler void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; @@ -201,7 +202,7 @@ namespace EMotionFX AZStd::vector m_attachments; AZStd::unique_ptr m_renderActorInstance; - bool m_debugDrawRoot; ///< Enables drawing of actor root and facing. + ActorRenderFlagBitset m_debugRenderFlags; ///< Actor debug render flag AzPhysics::SceneEvents::OnSceneSimulationFinishHandler m_sceneFinishSimHandler; }; diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp index 5da9716d15..d0274b3c68 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.cpp @@ -180,6 +180,7 @@ namespace EMotionFX , m_lodLevel(0) , m_actorAsset(AZ::Data::AssetLoadBehavior::NoLoad) { + m_debugRenderFlags[RENDER_SOLID] = true; } ////////////////////////////////////////////////////////////////////////// @@ -604,11 +605,10 @@ namespace EMotionFX m_renderActorInstance->OnTick(deltaTime); m_renderActorInstance->UpdateBounds(); - RenderActorInstance::DebugOptions debugOptions; - debugOptions.m_drawAABB = m_renderBounds; - debugOptions.m_drawSkeleton = m_renderSkeleton; - debugOptions.m_emfxDebugDraw = true; - m_renderActorInstance->DebugDraw(debugOptions); + m_debugRenderFlags[RENDER_AABB] = m_renderBounds; + m_debugRenderFlags[RENDER_SKELETON] = m_renderSkeleton; + m_debugRenderFlags[RENDER_EMFX_DEBUG] = true; + m_renderActorInstance->DebugDraw(m_debugRenderFlags); } } @@ -951,5 +951,10 @@ namespace EMotionFX LmbrCentral::AttachmentComponentRequestBus::Event(attachment, &LmbrCentral::AttachmentComponentRequestBus::Events::Reattach, true); } } + + void EditorActorComponent::SetRenderFlag(ActorRenderFlagBitset renderFlags) + { + m_debugRenderFlags = renderFlags; + } } //namespace Integration } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h index 1d682b47d4..f4c663a92f 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h +++ b/Gems/EMotionFX/Code/Source/Integration/Editor/Components/EditorActorComponent.h @@ -104,6 +104,8 @@ namespace EMotionFX ActorComponent::GetRequiredServices(required); } + void SetRenderFlag(ActorRenderFlagBitset renderFlags); + static void Reflect(AZ::ReflectContext* context); private: @@ -162,6 +164,7 @@ namespace EMotionFX size_t m_lodLevel; ActorComponent::BoundingBoxConfiguration m_bboxConfig; bool m_forceUpdateJointsOOV = false; + ActorRenderFlagBitset m_debugRenderFlags; ///< Actor debug render flag // \todo attachmentTarget node nr // Note: LOD work in progress. For now we use one material instead of a list of material, because we don't have the support for LOD with multiple scene files. diff --git a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorInstance.h b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorInstance.h index 47da0d4cca..8afb2a2f9a 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorInstance.h +++ b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorInstance.h @@ -16,6 +16,7 @@ #include #include +#include namespace EMotionFX { @@ -33,16 +34,7 @@ namespace EMotionFX virtual ~RenderActorInstance() = default; virtual void OnTick(float timeDelta) = 0; - - struct DebugOptions - { - bool m_drawAABB = false; - bool m_drawSkeleton = false; - bool m_drawRootTransform = false; - AZ::Transform m_rootWorldTransform = AZ::Transform::CreateIdentity(); - bool m_emfxDebugDraw = false; - }; - virtual void DebugDraw(const DebugOptions& debugOptions) = 0; + virtual void DebugDraw(const EMotionFX::ActorRenderFlagBitset& renderFlags) = 0; SkinningMethod GetSkinningMethod() const; virtual void SetSkinningMethod(SkinningMethod skinningMethod); diff --git a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderFlag.h b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderFlag.h new file mode 100644 index 0000000000..e053eae6d5 --- /dev/null +++ b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderFlag.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 + * + */ +#pragma once + +#include + +namespace EMotionFX +{ + enum ActorRenderFlag + { + RENDER_SOLID = 0, + RENDER_WIREFRAME = 1, + RENDER_LIGHTING = 2, + RENDER_SHADOWS = 3, + RENDER_FACENORMALS = 4, + RENDER_VERTEXNORMALS = 5, + RENDER_TANGENTS = 6, + RENDER_AABB = 7, + RENDER_SKELETON = 8, + RENDER_LINESKELETON = 9, + RENDER_NODEORIENTATION = 10, + RENDER_NODENAMES = 11, + RENDER_GRID = 12, + RENDER_BACKFACECULLING = 13, + RENDER_ACTORBINDPOSE = 14, + RENDER_RAGDOLL_COLLIDERS = 15, + RENDER_RAGDOLL_JOINTLIMITS = 16, + RENDER_HITDETECTION_COLLIDERS = 17, + RENDER_USE_GRADIENTBACKGROUND = 18, + RENDER_MOTIONEXTRACTION = 19, + RENDER_CLOTH_COLLIDERS = 20, + RENDER_SIMULATEDOBJECT_COLLIDERS = 21, + RENDER_SIMULATEJOINTS = 22, + RENDER_EMFX_DEBUG = 23, + NUM_RENDERFLAGS = 24 + }; + + using ActorRenderFlagBitset = AZStd::bitset; +} diff --git a/Gems/EMotionFX/Code/Tests/RenderBackendManagerTests.cpp b/Gems/EMotionFX/Code/Tests/RenderBackendManagerTests.cpp index 89d6fab93b..be990f444c 100644 --- a/Gems/EMotionFX/Code/Tests/RenderBackendManagerTests.cpp +++ b/Gems/EMotionFX/Code/Tests/RenderBackendManagerTests.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ namespace EMotionFX } MOCK_METHOD1(OnTick, void(float)); - MOCK_METHOD1(DebugDraw, void(const DebugOptions&)); + MOCK_METHOD1(DebugDraw, void(const EMotionFX::ActorRenderFlagBitset&)); MOCK_CONST_METHOD0(IsVisible, bool()); MOCK_METHOD1(SetIsVisible, void(bool)); MOCK_METHOD1(SetMaterials, void(const ActorAsset::MaterialList&)); From dc25cc099d1328e7f49ab3c52879bf80ef30299c Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 26 Oct 2021 02:29:12 -0700 Subject: [PATCH 063/200] Bug Fix: resolve entity ordering for EntityOutliner (#4798) (#4938) * bugifx: resolve dragging behaviour for EntityOutliner (#4798) Signed-off-by: Michael Pollind * chore: cleanup and rework logic Signed-off-by: Michael Pollind Signed-off-by: Gene Walters --- .../UI/Outliner/EntityOutlinerListModel.cpp | 50 ++++++++++++------- .../UI/Outliner/EntityOutlinerListModel.hxx | 9 +++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp index a5f1e29942..434a1d8303 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp @@ -943,13 +943,15 @@ namespace AzToolsFramework { return false; } - + + const int count = rowCount(parent); AZ::EntityId newParentId = GetEntityFromIndex(parent); - AZ::EntityId beforeEntityId = GetEntityFromIndex(index(row, 0, parent)); + AZ::EntityId beforeEntityId = (row >= 0 && row < count) ? GetEntityFromIndex(index(row, 0, parent)) : AZ::EntityId(); EntityIdList topLevelEntityIds; topLevelEntityIds.reserve(entityIdListContainer.m_entityIds.size()); ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::FindTopLevelEntityIdsInactive, entityIdListContainer.m_entityIds, topLevelEntityIds); - if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId)) + const auto appendActionForInvalid = newParentId.IsValid() && (row >= count) ? AppendEnd : AppendBeginning; + if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId, appendActionForInvalid)) { return false; } @@ -1046,7 +1048,7 @@ namespace AzToolsFramework return true; } - bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId) + bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId, ReparentForInvalid forInvalid) { AZ_PROFILE_FUNCTION(AzToolsFramework); if (!CanReparentEntities(newParentId, selectedEntityIds)) @@ -1056,10 +1058,18 @@ namespace AzToolsFramework m_isFilterDirty = true; - ScopedUndoBatch undo("Reparent Entities"); //capture child entity order before re-parent operation, which will automatically add order info if not present EntityOrderArray entityOrderArray = GetEntityChildOrder(newParentId); + //search for the insertion entity in the order array + const auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId); + const bool hasInvalidIndex = beforeEntityItr == entityOrderArray.end(); + if (hasInvalidIndex && forInvalid == None) + { + return false; + } + + ScopedUndoBatch undo("Reparent Entities"); // The new parent is dirty due to sort change(s) undo.MarkEntityDirty(GetEntityIdForSortInfo(newParentId)); @@ -1088,9 +1098,7 @@ namespace AzToolsFramework } } - //search for the insertion entity in the order array - auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId); - + //replace order info matching selection with bad values rather than remove to preserve layout for (auto& id : entityOrderArray) { @@ -1100,17 +1108,25 @@ namespace AzToolsFramework } } - if (newParentId.IsValid()) + //if adding to a valid parent entity, insert at the found entity location or at the head/tail depending on placeAtTail flag + if (hasInvalidIndex) { - //if adding to a valid parent entity, insert at the found entity location or at the head of the container - auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.begin(); - entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end()); - } - else + switch(forInvalid) + { + case AppendEnd: + entityOrderArray.insert(entityOrderArray.end(), processedEntityIds.begin(), processedEntityIds.end()); + break; + case AppendBeginning: + entityOrderArray.insert(entityOrderArray.begin(), processedEntityIds.begin(), processedEntityIds.end()); + break; + default: + AZ_Assert(false, "Unexpected type for ReparentForInvalid"); + break; + } + } + else { - //if adding to an invalid parent entity (the root), insert at the found entity location or at the tail of the container - auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.end(); - entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end()); + entityOrderArray.insert(beforeEntityItr, processedEntityIds.begin(), processedEntityIds.end()); } //remove placeholder entity ids diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx index 8176867038..0a46ee4850 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx @@ -72,6 +72,13 @@ namespace AzToolsFramework ColumnCount //!< Total number of columns }; + enum ReparentForInvalid + { + None, //!< For an invalid location the entity does not change location + AppendEnd, //!< Append Item to end of target parent list + AppendBeginning, //!< Append Item to the beginning of target parent list + }; + // Note: the ColumnSortIndex column isn't shown, hence the -1 and the need for a separate counter. // A wrong column count number causes refresh issues and hover mismatch on model update. static const int VisibleColumnCount = ColumnCount - 1; @@ -162,7 +169,7 @@ namespace AzToolsFramework // Buffer Processing Slots - These are called using single-shot events when the buffers begin to fill. bool CanReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds) const; - bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId()); + bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId(), ReparentForInvalid forInvalid = None); //! Use the current filter setting and re-evaluate the filter. void InvalidateFilter(); From 0c7df470ddb43c3257137a0c7d94fcfddf714fd6 Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Tue, 26 Oct 2021 08:29:43 -0700 Subject: [PATCH 064/200] Fixed crash if you save a bundle outside the default bundle folder (#4974) Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Signed-off-by: Gene Walters --- .../source/models/AssetBundlerAbstractFileTableModel.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp index 45d01b9b5b..8def0a698c 100644 --- a/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp +++ b/Code/Tools/AssetBundler/source/models/AssetBundlerAbstractFileTableModel.cpp @@ -61,8 +61,12 @@ namespace AssetBundler { AZStd::string absolutePath = filePath.toUtf8().data(); if (AZ::IO::FileIOBase::GetInstance()->Exists(absolutePath.c_str())) - { - AZStd::string projectName = pathToProjectNameMap.at(absolutePath); + { + AZStd::string projectName; + if (pathToProjectNameMap.contains(absolutePath)) + { + projectName = pathToProjectNameMap.at(absolutePath); + } // If a project name is already specified, then the associated file is a default file LoadFile(absolutePath, projectName, !projectName.empty()); From ebfea8a7e0ed935b8eba8d4c3d4fde85ff9a1309 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 26 Oct 2021 10:31:31 -0500 Subject: [PATCH 065/200] Moved the Asset Catalog loading from LmbrCentral to the AzFramework::Application (#4568) * Moved the loading of the AssetCatalog from LmbrCentralSystemComponent to AzFramework Application Modified the AssetCatalog::InitializeCatalog function to no longer rely on the TickBus to send out the `AssetCatalogEventBus::OnCatalogLoaded` event. It now queues a function on the AssetCatalogRequestBus to send the OnCatalogLoaded event as soon as the dispatching for the AssetCatalogRequestBus has completed on the current thread. This is done by updating the AssetCatalogRequestBus to use EBus ThreadDispatchPolicy to add a callback to invoke any queued function has soon a thread has finished dispatching and has released its DispatchMutex Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AssetCatalogRequestBus to add a custom DispatchLockGuard The AssetCatalogRequestBus uses the custom lock guard to dispatch queued events after it has unlocked it's context mutex for the current thread. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed GetContext call from the AssetCatalogRequests::PostThreadDispatchInvoker Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the definition of FileTagQueryManager::GetDefaultFileTagFilePath function to return a path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AZ_CONSOLEFREEFUNC macro to actually use the _NAME The _NAME parameter was not being used before, resulting in the Console stringified name of the function being used. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed CrySystem dependencies from the BundlingSystemComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Moved the loading of the AssetCatalog from LmbrCentralSystemComponent to AzFramework Application Modified the AssetCatalog::InitializeCatalog function to no longer rely on the TickBus to send out the `AssetCatalogEventBus::OnCatalogLoaded` event. It now queues a function on the AssetCatalogRequestBus to send the OnCatalogLoaded event as soon as the dispatching for the AssetCatalogRequestBus has completed on the current thread. This is done by updating the AssetCatalogRequestBus to use EBus ThreadDispatchPolicy to add a callback to invoke any queued function has soon a thread has finished dispatching and has released its DispatchMutex Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AssetCatalogRequestBus to add a custom DispatchLockGuard The AssetCatalogRequestBus uses the custom lock guard to dispatch queued events after it has unlocked it's context mutex for the current thread. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed GetContext call from the AssetCatalogRequests::PostThreadDispatchInvoker Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the definition of FileTagQueryManager::GetDefaultFileTagFilePath function to return a path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AZ_CONSOLEFREEFUNC macro to actually use the _NAME The _NAME parameter was not being used before, resulting in the Console stringified name of the function being used. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed CrySystem dependencies from the BundlingSystemComponent Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Addded missing template parameter to AssetCatalogRequests The fixes the compile error. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Adding AssetBus::MultiHandler::BusDisconnect call The BlastSystemComponent was connecting to the Bus, but not disconnecting from it, causing an assert to fire to it being a multi-thread bus Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added support for DataDrive lifecycle events to the ComponentApplication The events are using the SettingsRegistry NotifyEvent to track when certain keys are modified to signal handlers. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Corrected invalid JSON creation in ModuleManager::DeactivateEntities Resolved clang warning about used type alias Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fix for dangling reference in lambda registered to the SettingsRegistry Notifier event This was causing the EditorPythonBinding tests to crash due to the following circumstances. First Python has created an instance of a SettingsRegistryProxy Second the SettingsRegistry sends an event during the time when the SettingsRegistryProxy exists. This issue was exposed due to the ComponentApplication Lifecycle events using the SettingsRegistry to dispatch during various times of the application workflow. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: Gene Walters --- .../AzCore/AzCore/Asset/AssetManagerBus.h | 42 +++++++- .../AzCore/Component/ComponentApplication.cpp | 22 ++++- .../AzCore/Component/ComponentApplication.h | 4 +- .../ComponentApplicationLifecycle.cpp | 87 +++++++++++++++++ .../Component/ComponentApplicationLifecycle.h | 54 +++++++++++ .../AzCore/AzCore/Console/IConsole.h | 2 +- .../AzCore/AzCore/Module/ModuleManager.cpp | 38 ++++++-- .../Settings/SettingsRegistryScriptUtils.cpp | 18 ++-- .../AzCore/AzCore/azcore_files.cmake | 2 + .../AzFramework/Application/Application.cpp | 39 +++++++- .../AzFramework/Asset/AssetCatalog.cpp | 15 +-- .../AzFramework/Asset/AssetRegistry.cpp | 1 + .../AzFramework/FileTag/FileTag.cpp | 21 ++-- .../AzFramework/AzFramework/FileTag/FileTag.h | 3 +- .../AzFramework/FileTag/FileTagComponent.cpp | 4 +- .../AzFramework/Tests/AssetCatalog.cpp | 4 +- Code/Legacy/CrySystem/IDebugCallStack.cpp | 4 +- .../SerializeContextTools/SliceConverter.cpp | 2 - .../Application/AtomToolsApplication.cpp | 2 - .../Components/BlastSystemComponent.cpp | 1 + .../Bundling/BundlingSystemComponent.cpp | 97 +++++++------------ .../Source/Bundling/BundlingSystemComponent.h | 17 +--- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 43 +------- Gems/LmbrCentral/Code/Source/LmbrCentral.h | 10 -- Registry/application_lifecycle_events.setreg | 31 ++++++ 25 files changed, 390 insertions(+), 173 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp create mode 100644 Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h create mode 100644 Registry/application_lifecycle_events.setreg diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h b/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h index f8e263d6b0..f76ea19589 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManagerBus.h @@ -65,8 +65,35 @@ namespace AZ ////////////////////////////////////////////////////////////////////////// // EBusTraits overrides - Application is a singleton - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - typedef AZStd::recursive_mutex MutexType; + static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + using MutexType = AZStd::recursive_mutex; + + static constexpr bool EnableEventQueue = true; + using EventQueueMutexType = AZStd::mutex; + struct PostThreadDispatchInvoker + { + ~PostThreadDispatchInvoker(); + }; + + template + struct ThreadDispatchLockGuard + { + ThreadDispatchLockGuard(DispatchMutex& contextMutex) + : m_lock{ contextMutex } + {} + ThreadDispatchLockGuard(DispatchMutex& contextMutex, AZStd::adopt_lock_t adopt_lock) + : m_lock{ contextMutex, adopt_lock } + {} + ThreadDispatchLockGuard(const ThreadDispatchLockGuard&) = delete; + ThreadDispatchLockGuard& operator=(const ThreadDispatchLockGuard&) = delete; + private: + PostThreadDispatchInvoker m_threadPolicyInvoker; + using LockType = AZStd::conditional_t, AZStd::scoped_lock>; + LockType m_lock; + }; + + template + using DispatchLockGuard = ThreadDispatchLockGuard; ////////////////////////////////////////////////////////////////////////// virtual ~AssetCatalogRequests() = default; @@ -200,6 +227,17 @@ namespace AZ using AssetCatalogRequestBus = AZ::EBus; + inline AssetCatalogRequests::PostThreadDispatchInvoker::~PostThreadDispatchInvoker() + { + if (!AssetCatalogRequestBus::IsInDispatchThisThread()) + { + if (AssetCatalogRequestBus::QueuedEventCount()) + { + AssetCatalogRequestBus::ExecuteQueuedEvents(); + } + } + } + /* * Events that AssetManager listens for */ diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index ba66d56379..dabf02e260 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -44,8 +45,6 @@ #include #include -#include -#include #include #include @@ -506,6 +505,16 @@ namespace AZ SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*m_settingsRegistry); + // The /O3DE/Application/LifecycleEvents array contains a valid set of lifecycle events + // Those lifecycle events are normally read from the /Registry + // which isn't merged until ComponentApplication::Create invokes MergeSettingsToRegistry + // So pre-populate the valid lifecycle even entries + ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "SystemAllocatorCreated"); + ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "SettingsRegistryAvailable"); + ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "ConsoleAvailable"); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SystemAllocatorCreated", R"({})"); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SettingsRegistryAvailable", R"({})"); + // Create the Module Manager m_moduleManager = AZStd::make_unique(); @@ -520,6 +529,7 @@ namespace AZ m_ownsConsole = true; m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead()); m_settingsRegistryConsoleFunctors = AZ::SettingsRegistryConsoleUtils::RegisterAzConsoleCommands(*m_settingsRegistry, *m_console); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ConsoleAvailable", R"({})"); } } @@ -551,6 +561,7 @@ namespace AZ { AZ::Interface::Unregister(m_console); delete m_console; + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ConsoleUnavailable", R"({})"); } m_moduleManager.reset(); @@ -558,6 +569,8 @@ namespace AZ if (AZ::SettingsRegistry::Get() == m_settingsRegistry.get()) { SettingsRegistry::Unregister(m_settingsRegistry.get()); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SettingsRegistryUnavailable", R"({})"); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "SystemAllocatorPendingDestruction", R"({})"); } m_settingsRegistry.reset(); @@ -672,6 +685,8 @@ namespace AZ ReflectionEnvironment::GetReflectionManager()->Reflect(azrtti_typeid(this), [this](ReflectContext* context) {Reflect(context); }); RegisterCoreComponents(); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ReflectionManagerAvailable", R"({})"); + TickBus::AllowFunctionQueuing(true); SystemTickBus::AllowFunctionQueuing(true); @@ -691,6 +706,7 @@ namespace AZ // Load the actual modules LoadModules(); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsLoaded", R"({})"); // Execute user.cfg after modules have been loaded but before processing any command-line overrides AZ::IO::FixedMaxPath platformCachePath; @@ -756,12 +772,14 @@ namespace AZ m_entities.rehash(0); // force free all memory DestroyReflectionManager(); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "ReflectionManagerUnavailable", R"({})"); static_cast(m_settingsRegistry.get())->ClearNotifiers(); static_cast(m_settingsRegistry.get())->ClearMergeEvents(); // Uninit and unload any dynamic modules. m_moduleManager->UnloadModules(); + ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "GemsUnloaded", R"({})"); NameDictionary::Destroy(); diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h index f2b1bb8905..6df93aff4e 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h @@ -175,6 +175,8 @@ namespace AZ bool m_loadDynamicModules = true; //! Used by test fixtures to ensure reflection occurs to edit context. bool m_createEditContext = false; + //! Indicates whether the AssetCatalog.xml should be loaded by default in Application::StartCommon + bool m_loadAssetCatalog = true; }; ComponentApplication(); @@ -356,7 +358,7 @@ namespace AZ /// Calculates the root directory of the engine. void CalculateEngineRoot(); - /// Calculates the directory where the bootstrap.cfg file resides. + /// Deprecated: The term "AppRoot" has no meaning void CalculateAppRoot(); template diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp new file mode 100644 index 0000000000..533d55ed27 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.cpp @@ -0,0 +1,87 @@ +/* + * 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 + +namespace AZ::ComponentApplicationLifecycle +{ + bool ValidateEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName) + { + using FixedValueString = SettingsRegistryInterface::FixedValueString; + using Type = SettingsRegistryInterface::Type; + FixedValueString eventRegistrationKey{ ApplicationLifecycleEventRegistrationKey }; + eventRegistrationKey += '/'; + eventRegistrationKey += eventName; + return settingsRegistry.GetType(eventRegistrationKey) == Type::Object; + } + + bool SignalEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName, AZStd::string_view eventValue) + { + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + using Format = AZ::SettingsRegistryInterface::Format; + + if (!ValidateEvent(settingsRegistry, eventName)) + { + AZ_Warning("ComponentApplicationLifecycle", false, R"(Cannot signal event %.*s. Name does 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; + } + auto eventRegistrationKey = FixedValueString::format("%.*s/%.*s", AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey), + AZ_STRING_ARG(eventName)); + + return settingsRegistry.MergeSettings(eventValue, Format::JsonMergePatch, eventRegistrationKey); + } + + bool RegisterEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName) + { + using FixedValueString = SettingsRegistryInterface::FixedValueString; + using Format = AZ::SettingsRegistryInterface::Format; + + if (!ValidateEvent(settingsRegistry, eventName)) + { + FixedValueString eventRegistrationKey{ ApplicationLifecycleEventRegistrationKey }; + eventRegistrationKey += '/'; + eventRegistrationKey += eventName; + return settingsRegistry.MergeSettings(R"({})", Format::JsonMergePatch, eventRegistrationKey); + } + + return true; + } + + bool RegisterHandler(AZ::SettingsRegistryInterface& settingsRegistry, AZ::SettingsRegistryInterface::NotifyEventHandler& handler, + AZ::SettingsRegistryInterface::NotifyCallback callback, AZStd::string_view eventName) + { + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + using Type = AZ::SettingsRegistryInterface::Type; + using NotifyEventHandler = AZ::SettingsRegistryInterface::NotifyEventHandler; + + if (!ValidateEvent(settingsRegistry, eventName)) + { + AZ_Warning("ComponentApplicationLifecycle", false, R"(Cannot register event %.*s. Name does 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; + } + auto eventNameRegistrationKey = FixedValueString::format("%.*s/%.*s", AZ_STRING_ARG(ApplicationLifecycleEventRegistrationKey), + AZ_STRING_ARG(eventName)); + auto lifecycleCallback = [callback = AZStd::move(callback), eventNameRegistrationKey](AZStd::string_view path, Type type) + { + if (path == eventNameRegistrationKey) + { + callback(path, type); + } + }; + + handler = NotifyEventHandler(AZStd::move(lifecycleCallback)); + settingsRegistry.RegisterNotifier(handler); + + return true; + } +} diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h new file mode 100644 index 0000000000..5fc6c4b2c3 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplicationLifecycle.h @@ -0,0 +1,54 @@ +/* + * 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 + +#include +#include + +namespace AZ::ComponentApplicationLifecycle +{ + //! Root Key where lifecycle events should be registered under + inline constexpr AZStd::string_view ApplicationLifecycleEventRegistrationKey = "/O3DE/Runtime/Application/LifecycleEvents"; + + + //! Validates that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey + //! @param settingsRegistry registry where @eventName will be searched + //! @param eventName name of key that validated that exists as an element in the ApplicationLifecycleEventRegistrationKey array + //! @return true if the @eventName was found in the ApplicationLifecycleEventRegistrationKey array + bool ValidateEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName); + + //! Wrapper around setting a value underneath the ApplicationLifecycleEventRegistrationKey + //! It validates if the @eventName is is part of the ApplicationLifecycleEventRegistrationKey array + //! It then appends the @eventName to the ApplicationLifecycleEventRegistrationKey merges the @eventValue into + //! the SettingsRegistry at that key + //! NOTE: This function should only be invoked from ComponentApplication and its derived classes + //! @param settingsRegistry registry where eventName should be set + //! @param eventName name of key underneath the ApplicationLifecycleEventRegistrationKey to signal + //! @param eventValue JSON Object that will be merged into the SettingsRegistry at / + //! @return true if the eventValue was successfully merged at the / + bool SignalEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName, AZStd::string_view eventValue); + + //! Register that the event @eventName is stored in the array at ApplicationLifecycleEventRegistrationKey + //! @param settingsRegistry registry where @eventName will be searched + //! @param eventName name of key that will be stored in the ApplicationLifecycleEventRegistrationKey array + //! @return true if the event passed validation or the eventName was stored in the ApplicationLifecycleEventRegistrationKey array + bool RegisterEvent(AZ::SettingsRegistryInterface& settingsRegistry, AZStd::string_view eventName); + + //! Wrapper around registering the NotifyEventHandler with the SettingsRegistry for the specified event + //! It validates if the @eventName is is part of the ApplicationLifecycleEventRegistrationKey array and if + //! so moves the @callback into @handler and then registers the handler with the SettingsRegistry NotifyEvent + //! @param settingsRegistry registry where handler will be registered + //! @param handler handler where callback will be moved into and then registered with the SettingsRegistry + //! 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 + //! @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); +} diff --git a/Code/Framework/AzCore/AzCore/Console/IConsole.h b/Code/Framework/AzCore/AzCore/Console/IConsole.h index 73d17ac65a..aef163d22b 100644 --- a/Code/Framework/AzCore/AzCore/Console/IConsole.h +++ b/Code/Framework/AzCore/AzCore/Console/IConsole.h @@ -262,6 +262,6 @@ static constexpr AZ::ThreadSafety ConsoleThreadSafety<_TYPE, std::enable_if_t Functor##_FUNCTION(#_FUNCTION, _DESC, _FLAGS | AZ::ConsoleFunctorFlags::DontDuplicate, AZ::TypeId::CreateNull(), &_FUNCTION) + inline AZ::ConsoleFunctor Functor##_FUNCTION(_NAME, _DESC, _FLAGS | AZ::ConsoleFunctorFlags::DontDuplicate, AZ::TypeId::CreateNull(), &_FUNCTION) #define AZ_CONSOLEFREEFUNC(...) AZ_MACRO_SPECIALIZE(AZ_CONSOLEFREEFUNC_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__)) diff --git a/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp b/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp index 1fdeafa309..cbf3ce5243 100644 --- a/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp +++ b/Code/Framework/AzCore/AzCore/Module/ModuleManager.cpp @@ -10,16 +10,13 @@ #include #include -#include -#include #include #include #include -#include #include +#include +#include #include -#include -#include #include #include @@ -221,11 +218,16 @@ namespace AZ } } + AZStd::string componentNamesArray = R"({ "SystemComponents":[)"; + const char* comma = ""; // For all system components, deactivate for (auto componentIt = m_systemComponents.rbegin(); componentIt != m_systemComponents.rend(); ++componentIt) { ModuleEntity::DeactivateComponent(**componentIt); + componentNamesArray += AZStd::string::format(R"(%s"%s")", comma, (*componentIt)->RTTI_GetTypeName()); + comma = ", "; } + componentNamesArray += R"(]})"; // For all modules that we created an entity for, set them to "Init" (meaning not Activated) for (auto& moduleData : m_ownedModules) @@ -239,6 +241,13 @@ namespace AZ // Since the system components have been deactivated clear out the vector. m_systemComponents.clear(); + + // Signal that the System Components have deactivated + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "SystemComponentsDeactivated", componentNamesArray); + } + } //========================================================================= @@ -284,7 +293,11 @@ namespace AZ { // Split the tag list AZStd::vector tagList; - AZStd::tokenize(tags, ",", tagList); + auto TokenizeTags = [&tagList](AZStd::string_view token) + { + tagList.push_back(token); + }; + AZ::StringFunc::TokenizeVisitor(tags, TokenizeTags, ','); m_systemComponentTags.resize(tagList.size()); AZStd::transform(tagList.begin(), tagList.end(), m_systemComponentTags.begin(), [](const AZStd::string_view& tag) @@ -737,11 +750,17 @@ namespace AZ } } + AZStd::string componentNamesArray = R"({ "SystemComponents":[)"; + const char* comma = ""; // Activate the entities in the appropriate order for (Component* component : componentsToActivate) { ModuleEntity::ActivateComponent(*component); + + componentNamesArray += AZStd::string::format(R"(%s"%s")", comma, component->RTTI_GetTypeName()); + comma = ", "; } + componentNamesArray += R"(]})"; // Done activating; set state to active for (auto& moduleData : modulesToInit) @@ -755,5 +774,12 @@ namespace AZ // Save the activated components for deactivation later m_systemComponents.insert(m_systemComponents.end(), componentsToActivate.begin(), componentsToActivate.end()); + + // Signal that the System Components are activated + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + AZ::ComponentApplicationLifecycle::SignalEvent(*settingsRegistry, "SystemComponentsActivated", + componentNamesArray); + } } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp index c32591874b..5cd36785dc 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryScriptUtils.cpp @@ -15,20 +15,20 @@ namespace AZ::SettingsRegistryScriptUtils::Internal { - static void RegisterScriptProxyForNotify(SettingsRegistryScriptProxy& settingsRegistryProxy) + static void RegisterScriptProxyForNotify(SettingsRegistryInterface* settingsRegistry, + SettingsRegistryScriptProxy::NotifyEventProxy* notifyEventProxy) { - if (settingsRegistryProxy.IsValid()) + if (settingsRegistry != nullptr) { - auto ForwardSettingsUpdateToProxyEvent = [&settingsRegistryProxy](AZStd::string_view path, AZ::SettingsRegistryInterface::Type) + auto ForwardSettingsUpdateToProxyEvent = [notifyEventProxy](AZStd::string_view path, AZ::SettingsRegistryInterface::Type) { - if (settingsRegistryProxy.m_notifyEventProxy) + if (notifyEventProxy) { - settingsRegistryProxy.m_notifyEventProxy->m_scriptNotifyEvent.Signal(path); + notifyEventProxy->m_scriptNotifyEvent.Signal(path); } }; // Register the forwarding function with the BehaviorContext - settingsRegistryProxy.m_notifyEventProxy->m_settingsUpdatedHandler = - settingsRegistryProxy.m_settingsRegistry->RegisterNotifier(ForwardSettingsUpdateToProxyEvent); + notifyEventProxy->m_settingsUpdatedHandler = settingsRegistry->RegisterNotifier(ForwardSettingsUpdateToProxyEvent); } } @@ -37,7 +37,7 @@ namespace AZ::SettingsRegistryScriptUtils::Internal : m_settingsRegistry(AZStd::move(settingsRegistry)) , m_notifyEventProxy(AZStd::make_shared()) { - RegisterScriptProxyForNotify(*this); + RegisterScriptProxyForNotify(m_settingsRegistry.get(), m_notifyEventProxy.get()); } // Raw AZ::SettingsRegistryInterface pointer is not owned by the proxy, so it's deleter is a no-op @@ -45,7 +45,7 @@ namespace AZ::SettingsRegistryScriptUtils::Internal : m_settingsRegistry(settingsRegistry, [](AZ::SettingsRegistryInterface*) {}) , m_notifyEventProxy(AZStd::make_shared()) { - RegisterScriptProxyForNotify(*this); + RegisterScriptProxyForNotify(m_settingsRegistry.get(), m_notifyEventProxy.get()); } // SettingsRegistryScriptProxy function that determines if the SettingsRegistry object is valid diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 41229429f2..0c5a360844 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -41,6 +41,8 @@ set(FILES Component/ComponentApplication.cpp Component/ComponentApplication.h Component/ComponentApplicationBus.h + Component/ComponentApplicationLifecycle.cpp + Component/ComponentApplicationLifecycle.h Component/ComponentBus.cpp Component/ComponentBus.h Component/ComponentExport.h diff --git a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp index f8d0ea8bb1..8fb986802e 100644 --- a/Code/Framework/AzFramework/AzFramework/Application/Application.cpp +++ b/Code/Framework/AzFramework/AzFramework/Application/Application.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,11 @@ namespace AzFramework m_archiveFileIO = AZStd::make_unique(m_archive.get()); AZ::IO::FileIOBase::SetInstance(m_archiveFileIO.get()); SetFileIOAliases(); + // The FileIOAvailable event needs to be registered here as this event is sent out + // before the settings registry has merged the .setreg files from the + // (That happens in MergeSettingsToRegistry + AZ::ComponentApplicationLifecycle::RegisterEvent(*m_settingsRegistry, "FileIOAvailable"); + AZ::ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "FileIOAvailable", R"({})"); } if (auto nativeUI = AZ::Interface::Get(); nativeUI == nullptr) @@ -172,6 +178,8 @@ namespace AzFramework // Archive classes relies on the FileIOBase DirectInstance to close // files properly m_directFileIO.reset(); + + AZ::ComponentApplicationLifecycle::SignalEvent(*m_settingsRegistry, "FileIOUnavailable", R"({})"); } void Application::Start(const Descriptor& descriptor, const StartupParameters& startupParameters) @@ -196,7 +204,25 @@ namespace AzFramework systemEntity->Activate(); AZ_Assert(systemEntity->GetState() == AZ::Entity::State::Active, "System Entity failed to activate."); - m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); + + if (m_isStarted = (systemEntity->GetState() == AZ::Entity::State::Active); m_isStarted) + { + if (m_startupParameters.m_loadAssetCatalog) + { + // Start Monitoring Asset changes over the network and load the AssetCatalog + auto StartMonitoringAssetsAndLoadCatalog = [this](AZ::Data::AssetCatalogRequests* assetCatalogRequests) + { + if (AZ::IO::FixedMaxPath assetCatalogPath; + m_settingsRegistry->Get(assetCatalogPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_CacheRootFolder)) + { + assetCatalogPath /= "assetcatalog.xml"; + assetCatalogRequests->LoadCatalog(assetCatalogPath.c_str()); + } + }; + using AssetCatalogBus = AZ::Data::AssetCatalogRequestBus; + AssetCatalogBus::Broadcast(AZStd::move(StartMonitoringAssetsAndLoadCatalog)); + } + } } void Application::PreModuleLoad() @@ -210,6 +236,17 @@ namespace AzFramework { if (m_isStarted) { + if (m_startupParameters.m_loadAssetCatalog) + { + // Stop Monitoring Assets changes + auto StopMonitoringAssets = [](AZ::Data::AssetCatalogRequests* assetCatalogRequests) + { + assetCatalogRequests->StopMonitoringAssets(); + }; + using AssetCatalogBus = AZ::Data::AssetCatalogRequestBus; + AssetCatalogBus::Broadcast(AZStd::move(StopMonitoringAssets)); + } + ApplicationLifecycleEvents::Bus::Broadcast(&ApplicationLifecycleEvents::OnApplicationAboutToStop); m_pimpl.reset(); diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp index e6b8211c28..3d76bcefc4 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp @@ -565,7 +565,7 @@ namespace AzFramework if (!bytes.empty()) { - AZStd::shared_ptr < AzFramework::AssetRegistry> prevRegistry; + AZStd::shared_ptr prevRegistry; if (!m_initialized) { // First time initialization may have updates already processed which we want to apply @@ -589,7 +589,6 @@ namespace AzFramework AZ_TracePrintf("AssetCatalog", "Loaded registry containing %u assets.\n", m_registry->m_assetIdToInfo.size()); // It's currently possible in tools for us to have received updates from AP which were applied before the catalog was ready to load - // due to CryPak and CrySystem coming online later than our components if (!m_initialized) { ApplyDeltaCatalog(prevRegistry); @@ -611,12 +610,13 @@ namespace AzFramework // the mutex. If the listener tries to perform a blocking asset load via GetAsset() / BlockUntilLoadComplete(), the spawned asset // thread will make a call to the AssetCatalogRequestBus and block on the held mutex. This would cause a deadlock, since the listener // won't free the mutex until the load is complete. - // So instead, queue the notification until the next tick, so that it doesn't occur within the AssetCatalogRequestBus mutex, and also + // So instead, queue the notification until after the AssetCatalogRequestBus mutex is unlocked for the current thread, and also // so that the entire AssetCatalog initialization is complete. - AZ::TickBus::QueueFunction([catalogRegistryString = AZStd::string(catalogRegistryFile)]() - { - AssetCatalogEventBus::Broadcast(&AssetCatalogEventBus::Events::OnCatalogLoaded, catalogRegistryString.c_str()); - }); + auto OnCatalogLoaded = [catalogRegistryString = AZStd::string(catalogRegistryFile)]() + { + AssetCatalogEventBus::Broadcast(&AssetCatalogEventBus::Events::OnCatalogLoaded, catalogRegistryString.c_str()); + }; + AZ::Data::AssetCatalogRequestBus::QueueFunction(AZStd::move(OnCatalogLoaded)); } } @@ -978,6 +978,7 @@ namespace AzFramework AZStd::lock_guard lock(m_registryMutex); m_registry->Clear(); + m_initialized = false; } diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp index f9eefa7639..26a22f4625 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetRegistry.cpp @@ -61,6 +61,7 @@ namespace AzFramework //========================================================================= void AssetRegistry::Clear() { + m_assetDependencies = {}; m_assetIdToInfo = AssetIdToInfoMap(); m_assetPathToId = AssetPathToIdMap(); } diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp index f820ee56ed..abbb9ec2f1 100644 --- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp +++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.cpp @@ -10,11 +10,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -89,19 +89,19 @@ namespace AzFramework bool FileTagManager::Save(FileTagType fileTagType, const AZStd::string& destinationFilePath = AZStd::string()) { AzFramework::FileTag::FileTagAsset* fileTagAsset = GetFileTagAsset(fileTagType); - AZStd::string filePathToSave = destinationFilePath; + AZ::IO::Path filePathToSave = destinationFilePath; if (filePathToSave.empty()) { filePathToSave = FileTagQueryManager::GetDefaultFileTagFilePath(fileTagType); } - if (!AzFramework::StringFunc::EndsWith(filePathToSave, AzFramework::FileTag::FileTagAsset::Extension())) + if (!filePathToSave.Extension().Native().ends_with(AzFramework::FileTag::FileTagAsset::Extension())) { AZ_Error("FileTag", false, "Unable to save tag file (%s). Invalid file extension, file tag can only have (%s) extension.\n", filePathToSave.c_str(), AzFramework::FileTag::FileTagAsset::Extension()); return false; } - return AZ::Utils::SaveObjectToFile(filePathToSave, AZ::DataStream::StreamType::ST_XML, fileTagAsset); + return AZ::Utils::SaveObjectToFile(filePathToSave.Native(), AZ::DataStream::StreamType::ST_XML, fileTagAsset); } AZ::Outcome FileTagManager::AddTagsInternal(AZStd::string filePath, FileTagType fileTagType, AZStd::vector fileTags, AzFramework::FileTag::FilePatternType filePatternType) @@ -239,17 +239,22 @@ namespace AzFramework QueryFileTagsEventBus::Handler::BusDisconnect(); } - AZStd::string FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType fileTagType) + AZ::IO::Path FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType fileTagType) { - auto destinationFilePath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / EngineAssetSourceRelPath; + AZ::IO::Path destinationFilePath; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + settingsRegistry->Get(destinationFilePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); + } + destinationFilePath /= EngineAssetSourceRelPath; destinationFilePath /= fileTagType == FileTagType::Exclude ? ExcludeFileName : IncludeFileName; destinationFilePath.ReplaceExtension(AzFramework::FileTag::FileTagAsset::Extension()); - return destinationFilePath.String(); + return destinationFilePath; } bool FileTagQueryManager::Load(const AZStd::string& filePath) { - AZStd::string fileToLoad = filePath; + AZ::IO::Path fileToLoad = filePath; if (fileToLoad.empty()) { fileToLoad = GetDefaultFileTagFilePath(m_fileTagType); diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h index be3d6e6d08..d2dee3f629 100644 --- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h +++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTag.h @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace AzFramework @@ -88,7 +89,7 @@ namespace AzFramework ///////////////////////////////////////////////////////////////////////// - static AZStd::string GetDefaultFileTagFilePath(FileTagType fileTagType); + static AZ::IO::Path GetDefaultFileTagFilePath(FileTagType fileTagType); protected: diff --git a/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp b/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp index 1e03a6df0d..1d09500415 100644 --- a/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/FileTag/FileTagComponent.cpp @@ -16,6 +16,7 @@ #include #include +#include #include namespace AzFramework @@ -66,7 +67,8 @@ namespace AzFramework m_excludeFileQueryManager.reset(aznew FileTagQueryManager(FileTagType::Exclude)); if (!m_excludeFileQueryManager.get()->Load()) { - AZ_Error("FileTagQueryComponent", false, "Not able to load default exclude file (%s). Please make sure that it exists on disk.\n", FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType::Exclude).c_str()); + AZ_Error("FileTagQueryComponent", false, "Not able to load default exclude file (%s). Please make sure that it exists on disk.\n", + FileTagQueryManager::GetDefaultFileTagFilePath(FileTagType::Exclude).c_str()); } AzFramework::AssetCatalogEventBus::Handler::BusConnect(); diff --git a/Code/Framework/AzFramework/Tests/AssetCatalog.cpp b/Code/Framework/AzFramework/Tests/AssetCatalog.cpp index 8cdc54f34f..9e5c72f74c 100644 --- a/Code/Framework/AzFramework/Tests/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/Tests/AssetCatalog.cpp @@ -308,7 +308,9 @@ namespace UnitTest registry->Set(projectPathKey, "AutomatedTesting"); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(*registry); - m_app->Start(desc); + AZ::ComponentApplication::StartupParameters startupParameters; + startupParameters.m_loadAssetCatalog = false; + m_app->Start(desc, startupParameters); // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash diff --git a/Code/Legacy/CrySystem/IDebugCallStack.cpp b/Code/Legacy/CrySystem/IDebugCallStack.cpp index deb9c11581..a02658d34a 100644 --- a/Code/Legacy/CrySystem/IDebugCallStack.cpp +++ b/Code/Legacy/CrySystem/IDebugCallStack.cpp @@ -242,7 +242,7 @@ void IDebugCallStack::WriteLineToLog(const char* format, ...) va_end(ArgList); AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle; - AZ::IO::FileIOBase::GetDirectInstance()->Open("@Log@\\error.log", AZ::IO::GetOpenModeFromStringMode("a+t"), fileHandle); + AZ::IO::FileIOBase::GetDirectInstance()->Open("@log@\\error.log", AZ::IO::GetOpenModeFromStringMode("a+t"), fileHandle); if (fileHandle != AZ::IO::InvalidHandle) { AZ::IO::FileIOBase::GetDirectInstance()->Write(fileHandle, szBuffer, strlen(szBuffer)); @@ -254,7 +254,7 @@ void IDebugCallStack::WriteLineToLog(const char* format, ...) ////////////////////////////////////////////////////////////////////////// void IDebugCallStack::StartMemLog() { - AZ::IO::FileIOBase::GetDirectInstance()->Open("@Log@\\memallocfile.log", AZ::IO::OpenMode::ModeWrite, m_memAllocFileHandle); + AZ::IO::FileIOBase::GetDirectInstance()->Open("@log@\\memallocfile.log", AZ::IO::OpenMode::ModeWrite, m_memAllocFileHandle); assert(m_memAllocFileHandle != AZ::IO::InvalidHandle); } diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index 6cfe072f80..d0528a9cad 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -81,8 +81,6 @@ namespace AZ // Load the asset catalog so that we can find any nested assets successfully. We also need to tick the tick bus // so that the OnCatalogLoaded event gets processed now, instead of during application shutdown. - AZ::Data::AssetCatalogRequestBus::Broadcast( - &AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml"); application.Tick(); AZStd::string logggingScratchBuffer; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index e8ec77e7bd..ba3bfe4718 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -175,8 +175,6 @@ namespace AtomToolsFramework AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotificationBus::Broadcast( &AzToolsFramework::AssetBrowser::AssetDatabaseLocationNotifications::OnDatabaseInitialized); - AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::LoadCatalog, "@products@/assetcatalog.xml"); - if (!AZ::RPI::RPISystemInterface::Get()->IsInitialized()) { AZ::RPI::RPISystemInterface::Get()->InitializeSystemAssets(); diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index b7ee805b3c..00629eb65d 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -143,6 +143,7 @@ namespace Blast void BlastSystemComponent::Deactivate() { AZ_PROFILE_FUNCTION(Physics); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(); CrySystemEventBus::Handler::BusDisconnect(); AZ::TickBus::Handler::BusDisconnect(); BlastSystemRequestBus::Handler::BusDisconnect(); diff --git a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp index c9fc656488..168a3640a8 100644 --- a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.cpp @@ -9,43 +9,40 @@ #include "BundlingSystemComponent.h" #include +#include +#include #include #include +#include #include -#include - -#include -#include - #include + namespace LmbrCentral { const char bundleRoot[] = "@products@"; + // Calls the LoadBundles method + static void ConsoleCommandLoadBundles(const AZ::ConsoleCommandContainer& commandArgs); + // Calls the UnloadBundles method + static void ConsoleCommandUnloadBundles(const AZ::ConsoleCommandContainer& commandArgs); + + AZ_CONSOLEFREEFUNC("loadbundles", ConsoleCommandLoadBundles, AZ::ConsoleFunctorFlags::Null, "Load Asset Bundles"); + AZ_CONSOLEFREEFUNC("unloadbundles", ConsoleCommandUnloadBundles, AZ::ConsoleFunctorFlags::Null, "Unload Asset Bundles"); + void BundlingSystemComponent::Activate() { BundlingSystemRequestBus::Handler::BusConnect(); - CrySystemEventBus::Handler::BusConnect(); AZ::IO::ArchiveNotificationBus::Handler::BusConnect(); } void BundlingSystemComponent::Deactivate() { AZ::IO::ArchiveNotificationBus::Handler::BusDisconnect(); - CrySystemEventBus::Handler::BusDisconnect(); BundlingSystemRequestBus::Handler::BusDisconnect(); } - void BundlingSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) - { - AZ_UNUSED(systemInitParams); - - system.GetIConsole()->AddCommand("loadbundles", ConsoleCommandLoadBundles); - system.GetIConsole()->AddCommand("unloadbundles", ConsoleCommandUnloadBundles); - } - void BundlingSystemComponent::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) @@ -58,7 +55,7 @@ namespace LmbrCentral AZStd::vector BundlingSystemComponent::GetBundleList(const char* bundlePath, const char* bundleExtension) const { - AZStd::string fileFilter{ AZStd::string::format("*%s",bundleExtension) }; + AZStd::string fileFilter{ AZStd::string::format("*%s", bundleExtension) }; AZStd::vector bundleList; AZ::IO::FileIOBase::GetInstance()->FindFiles(bundlePath, fileFilter.c_str(), [&bundleList](const char* foundPath) -> bool @@ -73,29 +70,28 @@ namespace LmbrCentral return bundleList; } - void BundlingSystemComponent::ConsoleCommandLoadBundles(IConsoleCmdArgs* pCmdArgs) + void ConsoleCommandLoadBundles(const AZ::ConsoleCommandContainer& commandArgs) { const char defaultBundleFolder[] = "bundles"; const char defaultBundleExtension[] = ".pak"; - const char* bundleFolder = pCmdArgs->GetArgCount() > 1 ? pCmdArgs->GetArg(1) : defaultBundleFolder; - const char* bundleExtension = pCmdArgs->GetArgCount() > 2 ? pCmdArgs->GetArg(2) : defaultBundleExtension; + AZ::CVarFixedString bundleFolder = commandArgs.size() > 0 ? AZ::CVarFixedString(commandArgs[0]) : defaultBundleFolder; + AZ::CVarFixedString bundleExtension = commandArgs.size() > 1 ? AZ::CVarFixedString(commandArgs[1]) : defaultBundleExtension; - BundlingSystemRequestBus::Broadcast(&BundlingSystemRequestBus::Events::LoadBundles, bundleFolder, bundleExtension); + BundlingSystemRequestBus::Broadcast(&BundlingSystemRequestBus::Events::LoadBundles, bundleFolder.c_str(), bundleExtension.c_str()); } - void BundlingSystemComponent::ConsoleCommandUnloadBundles(IConsoleCmdArgs* pCmdArgs) + void ConsoleCommandUnloadBundles([[maybe_unused]] const AZ::ConsoleCommandContainer& commandArgs) { - AZ_UNUSED(pCmdArgs); BundlingSystemRequestBus::Broadcast(&BundlingSystemRequestBus::Events::UnloadBundles); } void BundlingSystemComponent::UnloadBundles() { - ISystem* crySystem{ GetISystem() }; - if (!crySystem) + auto archive = AZ::Interface::Get(); + if (!archive) { - AZ_Error("BundlingSystem", false, "Couldn't Get ISystem to unload bundles!"); + AZ_Error("BundlingSystem", false, "Couldn't Get IArchive to load bundles!"); return; } if (!m_bundleModeBundles.size()) @@ -106,7 +102,7 @@ namespace LmbrCentral AZStd::lock_guard openBundleLock(m_bundleModeMutex); for (const auto& thisBundle : m_bundleModeBundles) { - if (crySystem->GetIPak()->ClosePack(thisBundle.c_str())) + if (archive->ClosePack(thisBundle.c_str())) { AZ_TracePrintf("BundlingSystem", "Unloaded %s\n",thisBundle.c_str()); } @@ -128,15 +124,8 @@ namespace LmbrCentral return; } - ISystem* crySystem{ GetISystem() }; - if (!crySystem) - { - AZ_Error("BundlingSystem", false, "Couldn't Get ISystem to load bundles!"); - return; - } - - auto cryPak = crySystem->GetIPak(); - if (!cryPak) + auto archive = AZ::Interface::Get(); + if (!archive) { AZ_Error("BundlingSystem", false, "Couldn't Get IArchive to load bundles!"); return; @@ -152,8 +141,8 @@ namespace LmbrCentral } } AZStd::string bundlePath; - AzFramework::StringFunc::Path::Join(bundleRoot, thisBundle.c_str(), bundlePath); - if (cryPak->OpenPack(bundleRoot, thisBundle.c_str())) + AZ::StringFunc::Path::Join(bundleRoot, thisBundle.c_str(), bundlePath); + if (archive->OpenPack(bundleRoot, thisBundle.c_str())) { AZ_TracePrintf("BundlingSystem", "Loaded bundle %s\n",bundlePath.c_str()); m_bundleModeBundles.emplace_back(AZStd::move(bundlePath)); @@ -230,28 +219,21 @@ namespace LmbrCentral void BundlingSystemComponent::OpenDependentBundles(const char* bundleName, AZStd::shared_ptr bundleManifest) { - ISystem* crySystem{ GetISystem() }; - if (!crySystem) - { - AZ_Error("BundlingSystem", false, "Couldn't Get ISystem to load dependent bundles for %s", bundleName); - return; - } - - auto cryPak{ crySystem->GetIPak() }; - if (!cryPak) + auto archive = AZ::Interface::Get(); + if (!archive) { AZ_Error("BundlingSystem", false, "Couldn't Get IArchive to load dependent bundles for %s", bundleName); return; } AZStd::string folderPath; - AzFramework::StringFunc::Path::GetFolderPath(bundleName, folderPath); + AZ::StringFunc::Path::GetFolderPath(bundleName, folderPath); for (const auto& thisBundle : bundleManifest->GetDependentBundleNames()) { AZStd::string bundlePath; - AzFramework::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath); + AZ::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath); - if (!cryPak->OpenPack(bundleRoot, bundlePath.c_str())) + if (!archive->OpenPack(bundleRoot, bundlePath.c_str())) { // We're not bailing here intentionally - try to open the remaining bundles AZ_Warning("BundlingSystem", false, "Failed to open dependent bundle %s of bundle %s", bundlePath.c_str(), bundleName); @@ -300,28 +282,21 @@ namespace LmbrCentral void BundlingSystemComponent::CloseDependentBundles(const char* bundleName, AZStd::shared_ptr bundleManifest) { - ISystem* crySystem{ GetISystem() }; - if (!crySystem) - { - AZ_Error("BundlingSystem", false, "Couldn't get ISystem to close dependent bundles for %s", bundleName); - return; - } - - auto cryPak{ crySystem->GetIPak() }; - if (!cryPak) + auto archive = AZ::Interface::Get(); + if (!archive) { AZ_Error("BundlingSystem", false, "Couldn't get IArchive to close dependent bundles for %s", bundleName); return; } AZStd::string folderPath; - AzFramework::StringFunc::Path::GetFolderPath(bundleName, folderPath); + AZ::StringFunc::Path::GetFolderPath(bundleName, folderPath); for (const auto& thisBundle : bundleManifest->GetDependentBundleNames()) { AZStd::string bundlePath; - AzFramework::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath); + AZ::StringFunc::Path::Join(folderPath.c_str(), thisBundle.c_str(), bundlePath); - if (!cryPak->ClosePack(bundlePath.c_str())) + if (!archive->ClosePack(bundlePath.c_str())) { // We're not bailing here intentionally - try to close the remaining bundles AZ_Warning("BundlingSystem", false, "Failed to close dependent bundle %s of bundle %s", bundlePath.c_str(), bundleName); diff --git a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h index 15fdf1103c..e7c8775530 100644 --- a/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h +++ b/Gems/LmbrCentral/Code/Source/Bundling/BundlingSystemComponent.h @@ -19,11 +19,8 @@ #include -#include #include -struct IConsoleCmdArgs; - namespace AzFramework { class AssetBundleManifest; @@ -42,10 +39,9 @@ namespace LmbrCentral * System component for managing bundles */ class BundlingSystemComponent - : public AZ::Component, - public BundlingSystemRequestBus::Handler, - public CrySystemEventBus::Handler, - public AZ::IO::ArchiveNotificationBus::Handler + : public AZ::Component + , public BundlingSystemRequestBus::Handler + , public AZ::IO::ArchiveNotificationBus::Handler { public: AZ_COMPONENT(BundlingSystemComponent, "{0FB7153D-EE80-4B1C-9584-134270401AAF}"); @@ -70,13 +66,6 @@ namespace LmbrCentral void BundleOpened(const char* bundleName, AZStd::shared_ptr bundleManifest, const char* nextBundle, AZStd::shared_ptr bundleCatalog) override; void BundleClosed(const char* bundleName) override; - // CrySystemEventBus - void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override; - - // Calls the LoadBundles method - static void ConsoleCommandLoadBundles(IConsoleCmdArgs* pCmdArgs); - // Calls the UnloadBundles method - static void ConsoleCommandUnloadBundles(IConsoleCmdArgs* pCmdArgs); AZStd::vector GetBundleList(const char* bundlePath, const char* bundleExtension) const; diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index a5884ccce9..f167be8b84 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -84,8 +84,6 @@ namespace LmbrCentral { - static const char* s_assetCatalogFilename = "assetcatalog.xml"; - using LmbrCentralAllocatorScope = AZ::AllocatorScope; // This component boots the required allocators for LmbrCentral everywhere but AssetBuilders @@ -354,8 +352,7 @@ namespace LmbrCentral AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!"); // Add asset types and extensions to AssetCatalog. Uses "AssetCatalogService". - auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); - if (assetCatalog) + if (auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); assetCatalog) { assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); @@ -376,7 +373,6 @@ namespace LmbrCentral assetCatalog->AddExtension("cax"); } - CrySystemEventBus::Handler::BusConnect(); AZ::Data::AssetManagerNotificationBus::Handler::BusConnect(); @@ -448,7 +444,6 @@ namespace LmbrCentral m_unhandledAssetInfo.clear(); AZ::Data::AssetManagerNotificationBus::Handler::BusDisconnect(); - CrySystemEventBus::Handler::BusDisconnect(); // AssetHandler's destructor calls Unregister() m_assetHandlers.clear(); @@ -459,42 +454,6 @@ namespace LmbrCentral } m_allocatorShutdowns.clear(); } - - void LmbrCentralSystemComponent::OnCrySystemPreInitialize([[maybe_unused]] ISystem& system, [[maybe_unused]] const SSystemInitParams& systemInitParams) - { - EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, StartMonitoringAssets); - } - - void LmbrCentralSystemComponent::OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) - { -#if !defined(AZ_MONOLITHIC_BUILD) - // When module is linked dynamically, we must set our gEnv pointer. - // When module is linked statically, we'll share the application's gEnv pointer. - gEnv = system.GetGlobalEnvironment(); -#endif - - // Enable catalog now that application's asset root is set. - if (system.GetGlobalEnvironment()->IsEditor()) - { - // In the editor, we build the catalog by scanning the disk. - if (systemInitParams.pUserCallback) - { - systemInitParams.pUserCallback->OnInitProgress("Refreshing asset catalog..."); - } - } - - // load the catalog from disk (supported over VFS). - EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, LoadCatalog, AZStd::string::format("@products@/%s", s_assetCatalogFilename).c_str()); - } - - void LmbrCentralSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system) - { - EBUS_EVENT(AZ::Data::AssetCatalogRequestBus, StopMonitoringAssets); - -#if !defined(AZ_MONOLITHIC_BUILD) - gEnv = nullptr; -#endif - } } // namespace LmbrCentral #if !defined(LMBR_CENTRAL_EDITOR) diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.h b/Gems/LmbrCentral/Code/Source/LmbrCentral.h index 9a0c327ea7..650061dce6 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.h +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.h @@ -15,8 +15,6 @@ #include #include -#include - /*! * \namespace LmbrCentral * LmbrCentral ties together systems from CryEngine and systems from the AZ framework. @@ -49,7 +47,6 @@ namespace LmbrCentral */ class LmbrCentralSystemComponent : public AZ::Component - , private CrySystemEventBus::Handler , private AZ::Data::AssetManagerNotificationBus::Handler { public: @@ -71,13 +68,6 @@ namespace LmbrCentral void Deactivate() override; //////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////// - // CrySystemEvents - void OnCrySystemPreInitialize(ISystem& system, const SSystemInitParams& systemInitParams) override; - void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override; - void OnCrySystemShutdown(ISystem& system) override; - //////////////////////////////////////////////////////////////////////////// - AZStd::vector > m_assetHandlers; AZStd::vector > m_unhandledAssetInfo; AZStd::vector> m_allocatorShutdowns; diff --git a/Registry/application_lifecycle_events.setreg b/Registry/application_lifecycle_events.setreg new file mode 100644 index 0000000000..58baf267b0 --- /dev/null +++ b/Registry/application_lifecycle_events.setreg @@ -0,0 +1,31 @@ +// The Lifecycle events contains the name of the event as a string +// ComponentApplication derived classes +// will set these these keys to a JSON Object indicate an event has occured +// A callback can be registered with the SettingsRegistry +// to be notified when that key is set +// The JSON object that is set will contain any payload data +// related to the event +{ + "O3DE" : { + "Runtime": { + "Application": { + "LifecycleEvents": { + "SystemComponentsActivated": {}, + "SystemComponentsDeactivated": {}, + "ReflectionManagerAvailable": {}, + "ReflectionManagerUnavailable": {}, + "SystemAllocatorCreated": {}, + "SystemAllocatorPendingDestruction": {}, + "SettingsRegistryAvailable": {}, + "SettingsRegistryUnavailable": {}, + "ConsoleAvailable": {}, + "ConsoleUnavailable": {}, + "GemsLoaded": {}, + "GemsUnloaded": {}, + "FileIOAvailable": {}, + "FileIOUnavailable": {} + } + } + } + } +} From 0b4d3fa9305168f0ca5502d4be463ff830b28323 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 26 Oct 2021 10:52:33 -0500 Subject: [PATCH 066/200] [LYN-7529] Create unit tests for ResolveSourceFileDependencyPath (#4790) * Add unit tests for ResolveSourceFileDependencyPath Fix crash when file is not in scan folder Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Switch to using vector of AZ strings for better error output Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Switch to using UnorderedElementsAre Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add some comments and fix typo Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Signed-off-by: Gene Walters --- .../AssetManager/assetProcessorManager.cpp | 21 +-- .../AssetProcessorManagerTest.cpp | 139 ++++++++++++++++++ .../assetmanager/AssetProcessorManagerTest.h | 8 + 3 files changed, 158 insertions(+), 10 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp index fc806f6c9e..5e061491f0 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetProcessorManager.cpp @@ -3576,23 +3576,24 @@ namespace AssetProcessor // Absolute path, just check the 1 scan folder if (AZ::IO::PathView(encodedFileData.toUtf8().constData()).IsAbsolute()) { - QString scanFolderName; - if (!m_platformConfig->ConvertToRelativePath(encodedFileData, resultDatabaseSourceName, scanFolderName)) + auto scanFolderInfo = m_platformConfig->GetScanFolderForFile(encodedFileData); + + if (!m_platformConfig->ConvertToRelativePath(encodedFileData, scanFolderInfo, resultDatabaseSourceName)) { AZ_Warning( AssetProcessor::ConsoleChannel, false, "'%s' does not appear to be in any input folder. Use relative paths instead.", sourceDependency.m_sourceFileDependencyPath.c_str()); } + else + { + // Make an absolute path that is ScanFolderPath + Part of search path before the wildcard + QDir rooted(scanFolderInfo->ScanPath()); + QString scanFolderAndKnownSubPath = rooted.absoluteFilePath(knownPathBeforeWildcard); - auto scanFolderInfo = m_platformConfig->GetScanFolderByPath(scanFolderName); - - // Make an absolute path that is ScanFolderPath + Part of search path before the wildcard - QDir rooted(scanFolderName); - QString scanFolderAndKnownSubPath = rooted.absoluteFilePath(knownPathBeforeWildcard); - - resolvedDependencyList.append(m_platformConfig->FindWildcardMatches( - scanFolderAndKnownSubPath, relativeSearch, false, scanFolderInfo->RecurseSubFolders())); + resolvedDependencyList.append(m_platformConfig->FindWildcardMatches( + scanFolderAndKnownSubPath, relativeSearch, false, scanFolderInfo->RecurseSubFolders())); + } } else // Relative path, check every scan folder { diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index da6e995c97..6c19213414 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -88,6 +88,7 @@ public: friend struct DuplicateProductsTest; friend struct DuplicateProcessTest; friend struct AbsolutePathProductDependencyTest; + friend struct WildcardSourceDependencyTest; explicit AssetProcessorManager_Test(PlatformConfiguration* config, QObject* parent = nullptr); ~AssetProcessorManager_Test() override; @@ -5308,3 +5309,141 @@ TEST_F(MetadataFileTest, MetadataFile_SourceFileExtensionDifferentCase) ASSERT_TRUE(BlockUntilIdle(5000)); ASSERT_EQ(jobDetails.m_jobEntry.m_pathRelativeToWatchFolder, relFileName); } + +bool WildcardSourceDependencyTest::Test( + const AZStd::string& dependencyPath, AZStd::vector& resolvedPaths) +{ + [[maybe_unused]] QString resolvedName; + QStringList stringlistPaths; + 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()); + } + + return result; +} + +void WildcardSourceDependencyTest::SetUp() +{ + AssetProcessorManagerTest::SetUp(); + + QDir tempPath(m_tempDir.path()); + + // Add a non-recursive scan folder. Only files directly inside of this folder should be picked up, subfolders are ignored + m_config->AddScanFolder(ScanFolderInfo(tempPath.filePath("no_recurse"), "no_recurse", + "no_recurse", false, false, m_config->GetEnabledPlatforms(), 1)); + + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder1/1a.foo")); + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder1/1b.foo")); + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/a.foo")); + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/b.foo")); + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/folder/one/c.foo")); + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("subfolder2/redirected/folder/one/d.foo")); + + // Add a file that is not in a scanfolder. Should always be ignored + UnitTestUtils::CreateDummyFile(tempPath.absoluteFilePath("not/a/scanfolder/e.foo")); + + // 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")); +} + +TEST_F(WildcardSourceDependencyTest, Relative_Broad) +{ + // Expect all files except for the 2 invalid ones (e and f) + AZStd::vector resolvedPaths; + + ASSERT_TRUE(Test("*.foo", resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "b.foo", "folder/one/c.foo", "folder/one/d.foo", "1a.foo", "1b.foo")); +} + +TEST_F(WildcardSourceDependencyTest, Relative_WithFolder) +{ + // Make sure we can filter to files under a folder + AZStd::vector resolvedPaths; + + ASSERT_TRUE(Test("folder/*.foo", resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("folder/one/c.foo", "folder/one/d.foo")); +} + +TEST_F(WildcardSourceDependencyTest, Relative_WildcardPath) +{ + // Make sure the * wildcard works even if the full filename is given + AZStd::vector resolvedPaths; + + ASSERT_TRUE(Test("*a.foo", resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "1a.foo")); +} + +TEST_F(WildcardSourceDependencyTest, Absolute_WithFolder) +{ + // Make sure we can use absolute paths to filter to files under a folder + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_TRUE(Test(tempPath.absoluteFilePath("subfolder2/redirected/*.foo").toUtf8().constData(), resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre("a.foo", "b.foo", "folder/one/c.foo", "folder/one/d.foo")); +} + +TEST_F(WildcardSourceDependencyTest, Absolute_NotInScanfolder) +{ + // Files outside a scanfolder should not be returned even with an absolute path + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_TRUE(Test(tempPath.absoluteFilePath("not/a/scanfolder/*.foo").toUtf8().constData(), resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); +} + +TEST_F(WildcardSourceDependencyTest, Relative_NotInScanfolder) +{ + // Files outside a scanfolder should not be returned + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_TRUE(Test("*/e.foo", resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); +} + +TEST_F(WildcardSourceDependencyTest, Relative_InNonRecursiveScanfolder) +{ + // Files deep inside non-recursive scanfolders should not be returned + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_TRUE(Test("*/f.foo", resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); +} + +TEST_F(WildcardSourceDependencyTest, Absolute_InNonRecursiveScanfolder) +{ + // Absolute paths to files deep inside non-recursive scanfolders should not be returned + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_TRUE(Test(tempPath.absoluteFilePath("one/two/three/*.foo").toUtf8().constData(), resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); +} + +TEST_F(WildcardSourceDependencyTest, Relative_NoWildcard) +{ + // No wildcard results in a failure + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_FALSE(Test("subfolder1/1a.foo", resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); +} + +TEST_F(WildcardSourceDependencyTest, Absolute_NoWildcard) +{ + // No wildcard results in a failure + AZStd::vector resolvedPaths; + QDir tempPath(m_tempDir.path()); + + ASSERT_FALSE(Test(tempPath.absoluteFilePath("subfolder1/1a.foo").toUtf8().constData(), resolvedPaths)); + ASSERT_THAT(resolvedPaths, ::testing::UnorderedElementsAre()); +} diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h index 3443a4c519..94cc997938 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h @@ -131,6 +131,14 @@ struct MultiplatformPathDependencyTest void SetUp() override; }; +struct WildcardSourceDependencyTest + : AssetProcessorManagerTest +{ + bool Test(const AZStd::string& dependencyPath, AZStd::vector& resolvedPaths); + + void SetUp() override; +}; + struct MockBuilderInfoHandler : public AssetProcessor::AssetBuilderInfoBus::Handler { From 769e2e3942f94b356be604a0232c217425c0db63 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 26 Oct 2021 11:07:22 -0500 Subject: [PATCH 067/200] Add serialized output version (xml) of debug scene graph (#3437) * Add serialized output version (xml) of debug scene graph Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Fix line endings Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Fix line endings Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update fbx unit tests to check for dbgsg.xml file Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add dbgsg.xml comparison Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Move dbgsg files to SceneDebug sub folder Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add shaderball.dbgsg.xml and multiple_mesh_multiple_material_override.dbgsg.xml Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add shaderball dbgsg.xml product. Update code to look in SceneDebug for dbgsg files Fix extension concatenation Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Remove unnecessary dbgsg.xml file Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Signed-off-by: Gene Walters --- .../{ => SceneDebug}/Jack_Idle_Aim_ZUp.dbgsg | 12 +- .../SceneDebug/jack_idle_aim_zup.dbgsg.xml | 3223 ++++++ .../single_mesh_multiple_materials.dbgsg | 0 .../single_mesh_multiple_materials.dbgsg.xml | 849 ++ .../{ => SceneDebug}/onemeshonematerial.dbgsg | 0 .../SceneDebug/onemeshonematerial.dbgsg.xml | 519 + .../{ => SceneDebug}/shaderball.dbgsg | 0 .../SceneDebug/shaderball.dbgsg.xml | 9491 +++++++++++++++++ .../{ => SceneDebug}/lodtest.dbgsg | 0 .../SceneDebug/lodtest.dbgsg.xml | 2007 ++++ .../{ => SceneDebug}/physicstest.dbgsg | 0 .../SceneDebug/physicstest.dbgsg.xml | 817 ++ .../multiple_mesh_linked_materials.dbgsg | 0 .../multiple_mesh_linked_materials.dbgsg.xml | 1345 +++ .../multiple_mesh_one_material.dbgsg | 0 .../multiple_mesh_one_material.dbgsg.xml | 1015 ++ .../multiple_mesh_multiple_material.dbgsg | 0 .../multiple_mesh_multiple_material.dbgsg.xml | 1015 ++ ...iple_mesh_multiple_material_override.dbgsg | 0 ..._mesh_multiple_material_override.dbgsg.xml | 817 ++ .../{ => SceneDebug}/vertexcolor.dbgsg | 0 .../SceneDebug/vertexcolor.dbgsg.xml | 576 + .../assetpipeline/fbx_tests/fbx_tests.py | 99 +- Code/Tools/SceneAPI/SceneCore/DllMain.cpp | 1 + .../SceneCore/Utilities/DebugOutput.cpp | 75 +- .../SceneCore/Utilities/DebugOutput.h | 53 + .../SceneCore/Utilities/DebugOutput.inl | 10 +- 27 files changed, 21893 insertions(+), 31 deletions(-) rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/{ => SceneDebug}/Jack_Idle_Aim_ZUp.dbgsg (99%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/jack_idle_aim_zup.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/{ => SceneDebug}/single_mesh_multiple_materials.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/SceneDebug/single_mesh_multiple_materials.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/{ => SceneDebug}/onemeshonematerial.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/SceneDebug/onemeshonematerial.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/{ => SceneDebug}/shaderball.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/SceneDebug/shaderball.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/{ => SceneDebug}/lodtest.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/SceneDebug/lodtest.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/{ => SceneDebug}/physicstest.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/SceneDebug/physicstest.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/{ => SceneDebug}/multiple_mesh_linked_materials.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/SceneDebug/multiple_mesh_linked_materials.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/{ => SceneDebug}/multiple_mesh_one_material.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/SceneDebug/multiple_mesh_one_material.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/{ => SceneDebug}/multiple_mesh_multiple_material.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/{ => SceneDebug}/multiple_mesh_multiple_material_override.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material_override.dbgsg.xml rename AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/{ => SceneDebug}/vertexcolor.dbgsg (100%) create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/SceneDebug/vertexcolor.dbgsg.xml diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/Jack_Idle_Aim_ZUp.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/Jack_Idle_Aim_ZUp.dbgsg similarity index 99% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/Jack_Idle_Aim_ZUp.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/Jack_Idle_Aim_ZUp.dbgsg index 8b0132a448..c8c5c8697b 100644 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/Jack_Idle_Aim_ZUp.dbgsg +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/Jack_Idle_Aim_ZUp.dbgsg @@ -242,7 +242,7 @@ Node Type: BoneData BasisX: < 1.000000, -0.000000, 0.000000> BasisY: < 0.000000, 1.000000, 0.000000> BasisZ: <-0.000000, -0.000000, 1.000000> - Transl: < 0.152547, 0.043345, 0.090955> + Transl: < 0.152547, 0.043345, 0.090954> Node Name: animation Node Path: RootNode.jack_root.Bip01__pelvis.spine1.spine2.animation @@ -544,7 +544,7 @@ Node Type: BoneData Node Name: animation Node Path: RootNode.jack_root.Bip01__pelvis.spine1.spine2.spine3.l_shldr.l_upArm.l_upArmRoll.animation Node Type: AnimationData - KeyFrames: Count 195. Hash: 15529789169672670472 + KeyFrames: Count 195. Hash: 8781707605519483934 TimeStepBetweenFrames: 0.033333 Node Name: transform @@ -710,7 +710,7 @@ Node Type: BoneData BasisX: < 0.514369, 0.855813, 0.054857> BasisY: < 0.088153, 0.010863, -0.996047> BasisZ: <-0.853026, 0.517172, -0.069855> - Transl: <-0.247306, -0.062325, 0.878373> + Transl: <-0.247306, -0.062325, 0.878372> Node Name: animation Node Path: RootNode.jack_root.Bip01__pelvis.spine1.spine2.spine3.r_shldr.r_upArm.r_loArm.r_loArmRoll.animation @@ -857,7 +857,7 @@ Node Type: BoneData BasisX: < 0.329257, 0.944038, -0.019538> BasisY: < 0.465563, -0.180309, -0.866452> BasisZ: <-0.821487, 0.276189, -0.498877> - Transl: <-0.255124, -0.049696, 0.794467> + Transl: <-0.255124, -0.049696, 0.794466> Node Name: animation Node Path: RootNode.jack_root.Bip01__pelvis.spine1.spine2.spine3.l_shldr.l_upArm.l_loArm.l_hand.l_metacarpal.animation @@ -939,7 +939,6 @@ Node Type: AnimationData Node Name: transform Node Path: RootNode.jack_root.Bip01__pelvis.spine1.spine2.spine3.r_shldr.r_upArm.r_loArm.r_hand.r_index1.transform - Node Type: TransformData Matrix: BasisX: < 0.939162, 0.133704, -0.316383> @@ -954,7 +953,7 @@ Node Type: BoneData BasisX: <-0.102387, -0.418082, -0.902621> BasisY: < 0.928150, 0.286271, -0.237880> BasisZ: < 0.357847, -0.862123, 0.358732> - Transl: < 0.187367, 0.698324, 1.467209> + Transl: < 0.187367, 0.698323, 1.467209> Node Name: animation Node Path: RootNode.jack_root.Bip01__pelvis.spine1.spine2.spine3.r_shldr.r_upArm.r_loArm.r_hand.r_mid1.animation @@ -1513,3 +1512,4 @@ Node Type: TransformData BasisY: < 0.000000, 0.229519, -0.973304> BasisZ: < 0.000000, 0.973304, 0.229519> Transl: < 0.000000, -0.023770, 0.000000> + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/jack_idle_aim_zup.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/jack_idle_aim_zup.dbgsg.xml new file mode 100644 index 0000000000..caaf3810fe --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/Motion/SceneDebug/jack_idle_aim_zup.dbgsg.xml @@ -0,0 +1,3223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/single_mesh_multiple_materials.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/SceneDebug/single_mesh_multiple_materials.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/single_mesh_multiple_materials.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/SceneDebug/single_mesh_multiple_materials.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/SceneDebug/single_mesh_multiple_materials.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/SceneDebug/single_mesh_multiple_materials.dbgsg.xml new file mode 100644 index 0000000000..80b80fd67c --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshMultipleMaterials/SceneDebug/single_mesh_multiple_materials.dbgsg.xml @@ -0,0 +1,849 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/onemeshonematerial.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/SceneDebug/onemeshonematerial.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/onemeshonematerial.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/SceneDebug/onemeshonematerial.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/SceneDebug/onemeshonematerial.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/SceneDebug/onemeshonematerial.dbgsg.xml new file mode 100644 index 0000000000..87cc4fe260 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/OneMeshOneMaterial/SceneDebug/onemeshonematerial.dbgsg.xml @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/SceneDebug/shaderball.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/shaderball.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/SceneDebug/shaderball.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/SceneDebug/shaderball.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/SceneDebug/shaderball.dbgsg.xml new file mode 100644 index 0000000000..acff9e5f02 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/ShaderBall/SceneDebug/shaderball.dbgsg.xml @@ -0,0 +1,9491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/lodtest.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/SceneDebug/lodtest.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/lodtest.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/SceneDebug/lodtest.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/SceneDebug/lodtest.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/SceneDebug/lodtest.dbgsg.xml new file mode 100644 index 0000000000..d1af4198b5 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingLOD/SceneDebug/lodtest.dbgsg.xml @@ -0,0 +1,2007 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/physicstest.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/SceneDebug/physicstest.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/physicstest.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/SceneDebug/physicstest.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/SceneDebug/physicstest.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/SceneDebug/physicstest.dbgsg.xml new file mode 100644 index 0000000000..b22eb14fc6 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/SoftNamingPhysics/SceneDebug/physicstest.dbgsg.xml @@ -0,0 +1,817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/multiple_mesh_linked_materials.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/SceneDebug/multiple_mesh_linked_materials.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/multiple_mesh_linked_materials.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/SceneDebug/multiple_mesh_linked_materials.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/SceneDebug/multiple_mesh_linked_materials.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/SceneDebug/multiple_mesh_linked_materials.dbgsg.xml new file mode 100644 index 0000000000..3eaf018fb6 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshLinkedMaterials/SceneDebug/multiple_mesh_linked_materials.dbgsg.xml @@ -0,0 +1,1345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/multiple_mesh_one_material.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/SceneDebug/multiple_mesh_one_material.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/multiple_mesh_one_material.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/SceneDebug/multiple_mesh_one_material.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/SceneDebug/multiple_mesh_one_material.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/SceneDebug/multiple_mesh_one_material.dbgsg.xml new file mode 100644 index 0000000000..39ac33f654 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshOneMaterial/SceneDebug/multiple_mesh_one_material.dbgsg.xml @@ -0,0 +1,1015 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/multiple_mesh_multiple_material.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/multiple_mesh_multiple_material.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material.dbgsg.xml new file mode 100644 index 0000000000..c41c1414a4 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material.dbgsg.xml @@ -0,0 +1,1015 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/multiple_mesh_multiple_material_override.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material_override.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/multiple_mesh_multiple_material_override.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material_override.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material_override.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material_override.dbgsg.xml new file mode 100644 index 0000000000..01167ec0ee --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/TwoMeshTwoMaterial/SceneDebug/multiple_mesh_multiple_material_override.dbgsg.xml @@ -0,0 +1,817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/vertexcolor.dbgsg b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/SceneDebug/vertexcolor.dbgsg similarity index 100% rename from AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/vertexcolor.dbgsg rename to AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/SceneDebug/vertexcolor.dbgsg diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/SceneDebug/vertexcolor.dbgsg.xml b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/SceneDebug/vertexcolor.dbgsg.xml new file mode 100644 index 0000000000..f5caa70d63 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/assets/VertexColor/SceneDebug/vertexcolor.dbgsg.xml @@ -0,0 +1,576 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py index 5965db57b1..c28dfa64f2 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/fbx_tests/fbx_tests.py @@ -73,7 +73,12 @@ blackbox_fbx_tests = [ asset_db_utils.DBProduct( product_name='onemeshonematerial/onemeshonematerial.dbgsg', sub_id=1918494907, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='onemeshonematerial/onemeshonematerial.dbgsg.xml', + sub_id=556355570, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ) ] ), ] @@ -105,7 +110,12 @@ blackbox_fbx_tests = [ asset_db_utils.DBProduct( product_name='softnaminglod/lodtest.dbgsg', sub_id=-632012261, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='softnaminglod/lodtest.dbgsg.xml', + sub_id=-2036095434, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ) ] ), ] @@ -139,11 +149,16 @@ blackbox_fbx_tests = [ sub_id=-740411732, asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b' ), + asset_db_utils.DBProduct( + product_name='softnamingphysics/physicstest.dbgsg.xml', + sub_id=330338417, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ), asset_db_utils.DBProduct( product_name="softnamingphysics/physicstest.pxmesh", sub_id=640975857, asset_type=b"7a2871b95eab4de0a901b0d2c6920ddb" - ), + ) ] ), ] @@ -171,7 +186,11 @@ blackbox_fbx_tests = [ asset_db_utils.DBProduct( product_name='twomeshonematerial/multiple_mesh_one_material.dbgsg', sub_id=2077268018, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='twomeshonematerial/multiple_mesh_one_material.dbgsg.xml', + sub_id=1321067730, + asset_type=b'51f376140d774f369ac67ed70a0ac868') ] ), ] @@ -204,6 +223,11 @@ blackbox_fbx_tests = [ product_name='twomeshlinkedmaterials/multiple_mesh_linked_materials.dbgsg', sub_id=-1898461950, asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b' + ), + asset_db_utils.DBProduct( + product_name='twomeshlinkedmaterials/multiple_mesh_linked_materials.dbgsg.xml', + sub_id=-772341513, + asset_type=b'51f376140d774f369ac67ed70a0ac868' ) ] ), @@ -236,7 +260,12 @@ blackbox_fbx_tests = [ asset_db_utils.DBProduct( product_name='onemeshmultiplematerials/single_mesh_multiple_materials.dbgsg', sub_id=-262822238, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='onemeshmultiplematerials/single_mesh_multiple_materials.dbgsg.xml', + sub_id=1462358160, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ) ] ), ] @@ -266,7 +295,12 @@ blackbox_fbx_tests = [ asset_db_utils.DBProduct( product_name='vertexcolor/vertexcolor.dbgsg', sub_id=-1543877170, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='vertexcolor/vertexcolor.dbgsg.xml', + sub_id=1743516586, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ) ] ), ] @@ -297,6 +331,11 @@ blackbox_fbx_tests = [ product_name='motion/jack_idle_aim_zup.dbgsg', sub_id=-517610290, asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='motion/jack_idle_aim_zup.dbgsg.xml', + sub_id=-817863914, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ), asset_db_utils.DBProduct( product_name='motion/jack_idle_aim_zup.motion', sub_id=186392073, @@ -329,6 +368,10 @@ blackbox_fbx_tests = [ product_name='shaderball/shaderball.dbgsg', sub_id=-1607815784, asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='shaderball/shaderball.dbgsg.xml', + sub_id=-1153118555, + asset_type=b'51f376140d774f369ac67ed70a0ac868'), ] ), ] @@ -361,7 +404,12 @@ blackbox_fbx_special_tests = [ asset_db_utils.DBProduct( product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg', sub_id=896980093, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg.xml', + sub_id=-1556988544, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ) ] ), ] @@ -382,7 +430,12 @@ blackbox_fbx_special_tests = [ asset_db_utils.DBProduct( product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg', sub_id=896980093, - asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b') + asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'), + asset_db_utils.DBProduct( + product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg.xml', + sub_id=-1556988544, + asset_type=b'51f376140d774f369ac67ed70a0ac868' + ) ] ), ] @@ -454,6 +507,19 @@ class TestsFBX_AllPlatforms(object): product.product_name = job.platform + "/" \ + product.product_name + def compare_scene_debug_file(self, asset_processor, expected_file_path, actual_file_path): + debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(), actual_file_path) + expected_debug_graph_path = os.path.join(asset_processor.project_test_source_folder(), "SceneDebug", expected_file_path) + + logger.info(f"Parsing scene graph: {debug_graph_path}") + with open(debug_graph_path, "r") as scene_file: + actual_lines = scene_file.readlines() + + logger.info(f"Parsing scene graph: {expected_debug_graph_path}") + with open(expected_debug_graph_path, "r") as scene_file: + expected_lines = scene_file.readlines() + + assert utils.compare_lists(actual_lines, expected_lines), "Scene mismatch" def run_fbx_test(self, workspace, ap_setup_fixture, asset_processor, project, blackbox_params: BlackboxAssetTest, overrideAsset=False): """ @@ -509,19 +575,12 @@ class TestsFBX_AllPlatforms(object): scene_debug_file = blackbox_params.override_scene_debug_file if overrideAsset \ else blackbox_params.scene_debug_file - debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(), - blackbox_params.scene_debug_file) - expected_debug_graph_path = os.path.join(asset_processor.project_test_source_folder(), scene_debug_file) - - logger.info(f"Parsing scene graph: {debug_graph_path}") - with open(debug_graph_path, "r") as scene_file: - actual_lines = scene_file.readlines() - - logger.info(f"Parsing scene graph: {expected_debug_graph_path}") - with open(expected_debug_graph_path, "r") as scene_file: - expected_lines = scene_file.readlines() + self.compare_scene_debug_file(asset_processor, scene_debug_file, blackbox_params.scene_debug_file) - assert utils.compare_lists(actual_lines, expected_lines), "Scene mismatch" + # Run again for the .dbgsg.xml file + self.compare_scene_debug_file(asset_processor, + scene_debug_file + ".xml", + blackbox_params.scene_debug_file + ".xml") # Check that each given source asset resulted in the expected jobs and products. self.populateAssetInfo(workspace, project, assetsToValidate) diff --git a/Code/Tools/SceneAPI/SceneCore/DllMain.cpp b/Code/Tools/SceneAPI/SceneCore/DllMain.cpp index ad875f5538..51f081d8fa 100644 --- a/Code/Tools/SceneAPI/SceneCore/DllMain.cpp +++ b/Code/Tools/SceneAPI/SceneCore/DllMain.cpp @@ -187,6 +187,7 @@ namespace AZ // Register utilities AZ::SceneAPI::SceneCore::PatternMatcher::Reflect(context); + AZ::SceneAPI::Utilities::DebugSceneGraph::Reflect(context); } } diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp index de727498fc..41a030760e 100644 --- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,36 @@ namespace AZ::SceneAPI::Utilities { + void DebugNode::Reflect(AZ::ReflectContext* context) + { + AZ::SerializeContext* serialize = azrtti_cast(context); + + if (serialize) + { + serialize->Class() + ->Field("Name", &DebugNode::m_name) + ->Field("Path", &DebugNode::m_path) + ->Field("Type", &DebugNode::m_type) + ->Field("Data", &DebugNode::m_data); + } + } + + void DebugSceneGraph::Reflect(AZ::ReflectContext* context) + { + DebugNode::Reflect(context); + + AZ::SerializeContext* serialize = azrtti_cast(context); + + if (serialize) + { + serialize->Class() + ->Field("Version", &DebugSceneGraph::m_version) + ->Field("ProductName", &DebugSceneGraph::m_productName) + ->Field("SceneName", &DebugSceneGraph::m_sceneName) + ->Field("Nodes", &DebugSceneGraph::m_nodes); + } + } + void DebugOutput::Write(const char* name, const char* data) { m_output += AZStd::string::format("\t%s: %s\n", name, data); @@ -38,21 +69,29 @@ namespace AZ::SceneAPI::Utilities void DebugOutput::Write(const char* name, const AZStd::string& data) { Write(name, data.c_str()); + + AddToNode(name, data); } void DebugOutput::Write(const char* name, double data) { m_output += AZStd::string::format("\t%s: %f\n", name, data); + + AddToNode(name, data); } void DebugOutput::Write(const char* name, uint64_t data) { m_output += AZStd::string::format("\t%s: %" PRIu64 "\n", name, data); + + AddToNode(name, data); } void DebugOutput::Write(const char* name, int64_t data) { m_output += AZStd::string::format("\t%s: %" PRId64 "\n", name, data); + + AddToNode(name, data); } void DebugOutput::Write(const char* name, const DataTypes::MatrixType& data) @@ -63,6 +102,7 @@ namespace AZ::SceneAPI::Utilities AZ::Vector3 translation{}; data.GetBasisAndTranslation(&basisX, &basisY, &basisZ, &translation); + m_pauseNodeData = true; m_output += AZStd::string::format("\t%s:\n", name); m_output += "\t"; @@ -76,16 +116,23 @@ namespace AZ::SceneAPI::Utilities m_output += "\t"; Write("Transl", translation); + m_pauseNodeData = false; + + AddToNode(name, data); } void DebugOutput::Write(const char* name, bool data) { m_output += AZStd::string::format("\t%s: %s\n", name, data ? "true" : "false"); + + AddToNode(name, data); } void DebugOutput::Write(const char* name, Vector3 data) { m_output += AZStd::string::format("\t%s: <% f, % f, % f>\n", name, data.GetX(), data.GetY(), data.GetZ()); + + AddToNode(name, data); } void DebugOutput::Write(const char* name, AZStd::optional data) @@ -128,6 +175,11 @@ namespace AZ::SceneAPI::Utilities return m_output; } + DebugNode DebugOutput::GetDebugNode() const + { + return m_currentNode; + } + void WriteAndLog(AZ::IO::SystemFile& dbgFile, const char* strToWrite) { AZ_TracePrintf(AZ::SceneAPI::Utilities::LogWindow, "%s", strToWrite); @@ -137,7 +189,6 @@ namespace AZ::SceneAPI::Utilities void DebugOutput::BuildDebugSceneGraph(const char* outputFolder, AZ::SceneAPI::Events::ExportProductList& productList, const AZStd::shared_ptr& scene, AZStd::string productName) { - const int debugSceneGraphVersion = 1; AZStd::string debugSceneFile; AzFramework::StringFunc::Path::ConstructFull(outputFolder, productName.c_str(), debugSceneFile); @@ -147,7 +198,7 @@ namespace AZ::SceneAPI::Utilities if (dbgFile.Open(debugSceneFile.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY)) { WriteAndLog(dbgFile, AZStd::string::format("ProductName: %s", productName.c_str()).c_str()); - WriteAndLog(dbgFile, AZStd::string::format("debugSceneGraphVersion: %d", debugSceneGraphVersion).c_str()); + WriteAndLog(dbgFile, AZStd::string::format("debugSceneGraphVersion: %d", SceneGraphVersion).c_str()); WriteAndLog(dbgFile, scene->GetName().c_str()); const AZ::SceneAPI::Containers::SceneGraph& sceneGraph = scene->GetGraph(); @@ -158,6 +209,11 @@ namespace AZ::SceneAPI::Utilities AZ::SceneAPI::Containers::Views::BreadthFirst>( sceneGraph, sceneGraph.GetRoot(), pairView.cbegin(), true); + DebugSceneGraph debugSceneGraph; + debugSceneGraph.m_version = SceneGraphVersion; + debugSceneGraph.m_productName = productName; + debugSceneGraph.m_sceneName = scene->GetName().c_str(); + for (auto&& viewIt : view) { if (viewIt.second == nullptr) @@ -170,20 +226,31 @@ namespace AZ::SceneAPI::Utilities WriteAndLog(dbgFile, AZStd::string::format("Node Name: %s", viewIt.first.GetName()).c_str()); WriteAndLog(dbgFile, AZStd::string::format("Node Path: %s", viewIt.first.GetPath()).c_str()); WriteAndLog(dbgFile, AZStd::string::format("Node Type: %s", graphObject->RTTI_GetTypeName()).c_str()); - - AZ::SceneAPI::Utilities::DebugOutput debugOutput; + + AZ::SceneAPI::Utilities::DebugOutput debugOutput( + DebugNode(viewIt.first.GetName(), viewIt.first.GetPath(), graphObject->RTTI_GetTypeName())); + viewIt.second->GetDebugOutput(debugOutput); if (!debugOutput.GetOutput().empty()) { WriteAndLog(dbgFile, debugOutput.GetOutput().c_str()); } + + debugSceneGraph.m_nodes.push_back(debugOutput.GetDebugNode()); } dbgFile.Close(); + Utils::SaveObjectToFile((debugSceneFile + ".xml").c_str(), DataStream::StreamType::ST_XML, &debugSceneGraph); + static const AZ::Data::AssetType dbgSceneGraphAssetType("{07F289D1-4DC7-4C40-94B4-0A53BBCB9F0B}"); productList.AddProduct(productName, AZ::Uuid::CreateName(productName.c_str()), dbgSceneGraphAssetType, AZStd::nullopt, AZStd::nullopt); + + static const AZ::Data::AssetType dbgSceneGraphXmlAssetType("{51F37614-0D77-4F36-9AC6-7ED70A0AC868}"); + productList.AddProduct( + (productName + ".xml"), AZ::Uuid::CreateName((productName + ".xml").c_str()), dbgSceneGraphXmlAssetType, + AZStd::nullopt, AZStd::nullopt); } } } diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h index e05d10e2fa..533fb03a67 100644 --- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h +++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace AZ { @@ -34,15 +35,63 @@ namespace AZ namespace AZ::SceneAPI::Utilities { + constexpr int SceneGraphVersion = 1; + + struct DebugNode + { + AZ_TYPE_INFO(DebugNode, "{490B9D4C-1847-46EB-BEBC-49812E104626}"); + + AZStd::string m_name; + AZStd::string m_path; + AZStd::string m_type; + + DebugNode() = default; + + DebugNode(AZStd::string name, AZStd::string path, AZStd::string type) + : m_name(AZStd::move(name)), + m_path(AZStd::move(path)), + m_type(AZStd::move(type)) + { + } + + static void Reflect(AZ::ReflectContext* context); + + using DataItem = AZStd::pair; + AZStd::vector m_data; + }; + + struct DebugSceneGraph + { + AZ_TYPE_INFO(DebugSceneGraph, "{375F6558-5709-409F-881E-8ED575D56C92}"); + + int m_version = SceneGraphVersion; + AZStd::string m_productName; + AZStd::string m_sceneName; + AZStd::vector m_nodes; + + static void Reflect(AZ::ReflectContext* context); + }; + class DebugOutput { public: + DebugOutput(DebugNode node) : m_currentNode(AZStd::move(node)){} + template void Write(const char* name, const AZStd::vector& data); template void Write(const char* name, const AZStd::vector>& data); + template + void AddToNode(const char* name, const T& data) + { + if (!m_pauseNodeData) + { + m_currentNode.m_data.emplace_back(name, AZStd::make_any>(data)); + } + } + SCENE_CORE_API void Write(const char* name, const char* data); SCENE_CORE_API void WriteArray(const char* name, const unsigned int* data, int size); SCENE_CORE_API void Write(const char* name, const AZStd::string& data); @@ -57,11 +106,15 @@ namespace AZ::SceneAPI::Utilities SCENE_CORE_API void Write(const char* name, AZStd::optional data); SCENE_CORE_API const AZStd::string& GetOutput() const; + SCENE_CORE_API DebugNode GetDebugNode() const; SCENE_CORE_API static void BuildDebugSceneGraph(const char* outputFolder, AZ::SceneAPI::Events::ExportProductList& productList, const AZStd::shared_ptr& scene, AZStd::string productName); protected: AZStd::string m_output; + DebugSceneGraph m_graph; + DebugNode m_currentNode; + bool m_pauseNodeData = false; // If true, don't append any data to the DebugNode. Useful when a Write function calls other Write functions }; } diff --git a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.inl b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.inl index a139b4bce2..bba1d42ee9 100644 --- a/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.inl +++ b/Code/Tools/SceneAPI/SceneCore/Utilities/DebugOutput.inl @@ -13,7 +13,11 @@ namespace AZ::SceneAPI::Utilities template void DebugOutput::Write(const char* name, const AZStd::vector& data) { - m_output += AZStd::string::format("\t%s: Count %zu. Hash: %zu\n", name, data.size(), AZStd::hash_range(data.begin(), data.end())); + size_t hash = AZStd::hash_range(data.begin(), data.end()); + m_output += AZStd::string::format("\t%s: Count %zu. Hash: %zu\n", name, data.size(), hash); + + AddToNode(AZStd::string::format("%s - Count", name).c_str(), data.size()); + AddToNode(AZStd::string::format("%s - Hash", name).c_str(), hash); } template @@ -27,5 +31,9 @@ namespace AZ::SceneAPI::Utilities } m_output += AZStd::string::format("\t%s: Count %zu. Hash: %zu\n", name, data.size(), hash); + + AddToNode(AZStd::string::format("%s - Count", name).c_str(), data.size()); + AddToNode(AZStd::string::format("%s - Hash", name).c_str(), hash); } + } From 104170879e7affcdbf78bce652e1160c8d0f8460 Mon Sep 17 00:00:00 2001 From: SJ Date: Tue, 26 Oct 2021 09:43:03 -0700 Subject: [PATCH 068/200] Pass relative path IsFileExcluded so that only paths relative to the root scan folder are matched against the exclude filters (#4504) * Pass relative path IsFileExcluded so that only paths relative to the root scan folder are matched against the exclude filters. Signed-off-by: amzn-sj * Revert previous change. Remove the exclude filter for the Install directory. Signed-off-by: amzn-sj * Pass in relative path to the exclude filter as before. Fix the AssetScanner tests. Signed-off-by: amzn-sj * Prepend a ./ to the relative path in order to match the exclude patterns Signed-off-by: amzn-sj * Remove hack to prepend ./. Update the exclude patterns so that the hack is no longer required. Signed-off-by: amzn-sj * Add missing ? and remove whitespace Signed-off-by: amzn-sj * 1. IsFileExcluded() now converts the input path to a path that's relative to its corresponding scan folder. 2. Update regex patterns in gems and AutomatedTesting as well. 3. Remove unnecessary escaping for '/'. Signed-off-by: amzn-sj * Use ConvertToRelativePath() function to compute path relative to a scan folder. Signed-off-by: amzn-sj * More fixes to regex patterns Signed-off-by: amzn-sj * Remove test case which tests a hypothetical scenario that cannot occur. Fix another test case by adding scan folder. Signed-off-by: amzn-sj * Remove assert that's not needed since it's a valid scenario Signed-off-by: amzn-sj Signed-off-by: Gene Walters --- .../Gem/AssetProcessorGemConfig.setreg | 10 ++--- .../AssetCatalog/AssetCatalogUnitTests.cpp | 2 +- .../tests/assetscanner/AssetScannerTests.cpp | 4 +- .../platformconfigurationtests.cpp | 2 + .../AssetProcessorManagerUnitTests.cpp | 9 +---- .../utilities/PlatformConfiguration.cpp | 11 ++++-- .../AssetProcessorPlatformConfig.setreg | 4 +- .../AssetProcessorPlatformConfig.setreg | 4 +- .../AssetProcessorPlatformConfig.setreg | 2 +- .../AssetProcessorGemConfig.setreg | 4 +- Registry/AssetProcessorPlatformConfig.setreg | 38 ++++++++++--------- 11 files changed, 47 insertions(+), 43 deletions(-) diff --git a/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg b/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg index 043774c9cc..d4de26a2dc 100644 --- a/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg +++ b/AutomatedTesting/Gem/AssetProcessorGemConfig.setreg @@ -3,19 +3,19 @@ "AssetProcessor": { "Settings": { "Exclude PythonTest Benchmark Settings Assets": { - "pattern": ".*\\\\/PythonTests\\\\/.*benchmarksettings" + "pattern": "(^|.+/)PythonTests/.*benchmarksettings" }, "Exclude fbx_tests": { - "pattern": ".*\\\\/fbx_tests\\\\/assets\\\\/.*" + "pattern": "(^|.+/)fbx_tests/assets(/.+)$" }, "Exclude wwise_bank_dependency_tests": { - "pattern": ".*\\\\/wwise_bank_dependency_tests\\\\/assets\\\\/.*" + "pattern": "(^|.+/)wwise_bank_dependency_tests/assets(/.+)$" }, "Exclude AssetProcessorTestAssets": { - "pattern": ".*\\\\/asset_processor_tests\\\\/assets\\\\/.*" + "pattern": "(^|.+/)asset_processor_tests/assets(/.+)$" }, "Exclude Restricted AssetProcessorTestAssets": { - "pattern": ".*\\\\/asset_processor_tests\\\\/restricted\\\\/.*" + "pattern": "(^|.+/)asset_processor_tests/restricted(/.+)$" } } } diff --git a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp index 2a1c4e4755..46f801223a 100644 --- a/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/AssetCatalog/AssetCatalogUnitTests.cpp @@ -281,7 +281,7 @@ namespace AssetProcessor ExcludeAssetRecognizer excludeRecogniser; excludeRecogniser.m_name = "backup"; - excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); + excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); config.AddExcludeRecognizer(excludeRecogniser); } diff --git a/Code/Tools/AssetProcessor/native/tests/assetscanner/AssetScannerTests.cpp b/Code/Tools/AssetProcessor/native/tests/assetscanner/AssetScannerTests.cpp index 7bf9eb3cc5..9b4c4e4f40 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetscanner/AssetScannerTests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetscanner/AssetScannerTests.cpp @@ -123,7 +123,7 @@ namespace AssetProcessor ExcludeAssetRecognizer excludeRecogniser; excludeRecogniser.m_name = "backup"; // we are excluding all the files in the folder but not the folder itself - excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); + excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser); m_assetScanner.get()->StartScan(); @@ -144,7 +144,7 @@ namespace AssetProcessor ExcludeAssetRecognizer excludeRecogniser; excludeRecogniser.m_name = "backup"; // we are excluding the complete folder here - excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/subfolder2\\/aaa", AssetBuilderSDK::AssetBuilderPattern::Regex); + excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|[^/]+/)aaa", AssetBuilderSDK::AssetBuilderPattern::Regex); m_platformConfig.get()->AddExcludeRecognizer(excludeRecogniser); m_assetScanner.get()->StartScan(); diff --git a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp index 69397745f1..6fd05fa948 100644 --- a/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp +++ b/Code/Tools/AssetProcessor/native/tests/platformconfiguration/platformconfigurationtests.cpp @@ -405,6 +405,8 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes) auto configRoot = AZ::IO::FileIOBase::GetInstance()->ResolvePath("@exefolder@/testdata/config_regular"); ASSERT_TRUE(configRoot); UnitTestPlatformConfiguration config; + + config.AddScanFolder(ScanFolderInfo("blahblah", "Blah ScanFolder", "sf2", true, true), true); m_absorber.Clear(); ASSERT_TRUE(config.InitializeFromConfigFiles(configRoot->c_str(), testExeFolder->c_str(), EmptyDummyProjectName, false, false)); ASSERT_EQ(m_absorber.m_numErrorsAbsorbed, 0); diff --git a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp index c0e2c0f1d2..9efe755f16 100644 --- a/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/AssetProcessorManagerUnitTests.cpp @@ -347,7 +347,7 @@ namespace AssetProcessor ExcludeAssetRecognizer excludeRecogniser; excludeRecogniser.m_name = "backup"; - excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher(".*\\/savebackup\\/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); + excludeRecogniser.m_patternMatcher = AssetBuilderSDK::FilePatternMatcher("(^|.+/)savebackup/.*", AssetBuilderSDK::AssetBuilderPattern::Regex); config.AddExcludeRecognizer(excludeRecogniser); AssetProcessorManager_Test apm(&config); // note, this will 'push' the scan folders in to the db. @@ -1791,13 +1791,8 @@ namespace AssetProcessor UNIT_TEST_EXPECT_TRUE((newfingerprintForPCAfterVersionChange != fingerprintForPC) || (newfingerprintForPCAfterVersionChange != newfingerprintForPC));//Fingerprints should be different UNIT_TEST_EXPECT_TRUE((newfingerprintForANDROIDAfterVersionChange != fingerprintForANDROID) || (newfingerprintForANDROIDAfterVersionChange != newfingerprintForANDROID));//Fingerprints should be different - //------Test for Files which are excluded processResults.clear(); - absolutePath = AssetUtilities::NormalizeFilePath(tempPath.absoluteFilePath("subfolder3/savebackup/test.txt")); - QMetaObject::invokeMethod(&apm, "AssessModifiedFile", Qt::QueuedConnection, Q_ARG(QString, absolutePath)); - UNIT_TEST_EXPECT_FALSE(BlockUntil(idling, 3000)); //Processing a file that will be excluded should not cause assetprocessor manager to emit the onBecameIdle signal because its state should not change - UNIT_TEST_EXPECT_TRUE(processResults.size() == 0); - + // ------------- Test querying asset status ------------------- { absolutePath = tempPath.absoluteFilePath("subfolder2/folder/ship.tiff"); diff --git a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp index 9a60bf3110..bcadd0f103 100644 --- a/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/PlatformConfiguration.cpp @@ -1633,13 +1633,18 @@ namespace AssetProcessor bool AssetProcessor::PlatformConfiguration::IsFileExcluded(QString fileName) const { - for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers) + QString relPath, scanFolderName; + if (ConvertToRelativePath(fileName, relPath, scanFolderName)) { - if (excludeRecognizer.m_patternMatcher.MatchesPath(fileName.toUtf8().constData())) + for (const ExcludeAssetRecognizer& excludeRecognizer : m_excludeAssetRecognizers) { - return true; + if (excludeRecognizer.m_patternMatcher.MatchesPath(relPath.toUtf8().constData())) + { + return true; + } } } + return false; } diff --git a/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.setreg b/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.setreg index e4bee1b6de..11a77aefd4 100644 --- a/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.setreg +++ b/Code/Tools/AssetProcessor/testdata/config_regular/AssetProcessorPlatformConfig.setreg @@ -50,10 +50,10 @@ "order": 6000 }, "Exclude HoldFiles": { - "pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*" + "pattern": "(^|.+/)Levels/.*_hold(/.*)?$" }, "Exclude TempFiles": { - "pattern": ".*\\\\/\\\\$tmp[0-9]*_.*" + "pattern": "(^|.+/)\\\\$tmp[0-9]*_.*" }, "RC i_caf": { "glob": "*.i_caf", diff --git a/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.setreg b/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.setreg index c8fd13bf1f..a86a2168fd 100644 --- a/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.setreg +++ b/Code/Tools/AssetProcessor/testdata/config_regular_platform_scanfolder/AssetProcessorPlatformConfig.setreg @@ -74,10 +74,10 @@ "include": "test" }, "Exclude HoldFiles": { - "pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*" + "pattern": "(^|.+/)Levels/.*_hold(/.*)?$" }, "Exclude TempFiles": { - "pattern": ".*\\\\/\\\\$tmp[0-9]*_.*" + "pattern": "(^|.+/)\\\\$tmp[0-9]*_.*" }, "RC i_caf": { "glob": "*.i_caf", diff --git a/Gems/AtomContent/Sponza/Registry/AssetProcessorPlatformConfig.setreg b/Gems/AtomContent/Sponza/Registry/AssetProcessorPlatformConfig.setreg index 778d05dee9..206a0a2a87 100644 --- a/Gems/AtomContent/Sponza/Registry/AssetProcessorPlatformConfig.setreg +++ b/Gems/AtomContent/Sponza/Registry/AssetProcessorPlatformConfig.setreg @@ -6,7 +6,7 @@ // Sample Gems, Block source folders // ------------------------------------------------------------------------------ "Exclude Work In Progress Folders": { - "pattern": ".*\\\\/.[Ss]rc\\\\/.*" + "pattern": "(^|.+/).[Ss]rc(/.*)?$" } } } diff --git a/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg b/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg index 9b4d86791c..6d7995b230 100644 --- a/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg +++ b/Gems/AudioEngineWwise/AssetProcessorGemConfig.setreg @@ -3,10 +3,10 @@ "AssetProcessor": { "Settings": { "Exclude AudioProject": { - "pattern": ".*\\\\/Sounds\\\\/.+_project.*" + "pattern": "(^|.+/)Sounds/.+_project.*" }, "Exclude AudioTemp": { - "pattern": ".*\\\\/Sounds\\\\/.+\\\\.(txt|xml|dat)" + "pattern": "(^|.+/)Sounds/.+\\\\.(txt|xml|dat)" }, "RC audio": { "pattern": ".*\\\\.(wav|pcm)", diff --git a/Registry/AssetProcessorPlatformConfig.setreg b/Registry/AssetProcessorPlatformConfig.setreg index ddc465c201..c8d8dd9a80 100644 --- a/Registry/AssetProcessorPlatformConfig.setreg +++ b/Registry/AssetProcessorPlatformConfig.setreg @@ -137,64 +137,66 @@ // Excludes files that match the pattern or glob // if you use a pattern, remember to escape your backslashes (\\) + // The patterns are checked against a path relative to the entry's + // root scan folder. "Exclude _LevelBackups": { - "pattern": ".*\\\\/Levels\\\\/.*\\\\/_savebackup\\\\/.*" + "pattern": "(^|.+/)Levels/.*/_savebackup(/.*)?$" }, "Exclude _LevelAutoBackups": { - "pattern": ".*\\\\/Levels\\\\/.*\\\\/_autobackup\\\\/.*" + "pattern": "(^|.+/)Levels/.*/_autobackup(/.*)?$" }, "Exclude HoldFiles": { - "pattern": ".*\\\\/Levels\\\\/.*_hold\\\\/.*" + "pattern": "(^|.+/)Levels/.*_hold(/.*)?$" }, // note that $ has meaning to regex, so we escape it. "Exclude TempFiles": { - "pattern": ".*\\\\/\\\\$tmp[0-9]*_.*" + "pattern": "(^|.+/)\\\\$tmp[0-9]*_.*" }, "Exclude TmpAnimationCompression": { - "pattern": ".*\\\\/Editor\\\\/Tmp\\\\/AnimationCompression\\\\/.*" + "pattern": "(^|.+/)Editor/Tmp/AnimationCompression(/.*)?$" }, "Exclude EventLog": { - "pattern": ".*\\\\/Editor\\\\/.*eventlog\\\\.xml" + "pattern": "(^|.+/)Editor/.*eventlog\\\\.xml" }, "Exclude GameGemsCode": { - "pattern": ".*\\\\/Gem\\\\/Code\\\\/.*" + "pattern": "(^|.+/)Gem/Code(/.*)?$" }, "Exclude GameGemsResources": { - "pattern": ".*\\\\/Gem\\\\/Resources\\\\/.*" + "pattern": "(^|.+/)Gem/Resources(/.*)?$" }, "Exclude Private Certs": { - "pattern": ".*\\DynamicContent\\\\/Certificates\\\\/Private\\\\/.*" + "pattern": "(^|.+/)DynamicContent/Certificates/Private(/.*)?$" }, "Exclude CMakeLists": { - "pattern": ".*\\\\/CMakeLists.txt" + "pattern": "(^|.+/)CMakeLists\\\\.txt" }, "Exclude CMakeFiles": { - "pattern": ".*\\\\/.*\\\\.cmake" + "pattern": "(^|.+/).+\\\\.cmake" }, "Exclude User": { - "pattern": ".*/[Uu]ser/.*" + "pattern": "^[Uu]ser(/.*)?$" }, "Exclude Build": { - "pattern": ".*/[Bb]uild/.*" + "pattern": "^[Bb]uild(/.*)?$" }, "Exclude Install": { - "pattern": ".*/[Ii]nstall/.*" + "pattern": "^[Ii]nstall(/.*)?$" }, "Exclude UserSettings": { - "pattern": ".*/UserSettings.xml" + "pattern": "(^|[^/]+/)UserSettings\\\\.xml" }, // ------------------------------------------------------------------------------ // Large Worlds Test // ------------------------------------------------------------------------------ "Exclude Work In Progress Folders": { - "pattern": ".*\\\\/WIP\\\\/.*" + "pattern": "(^|[^/]+/)WIP(/.*)?" }, "Exclude Content Source Folders": { - "pattern": ".*\\\\/CONTENT_SOURCE\\\\/.*" + "pattern": "(^|[^/]+/)CONTENT_SOURCE(/.*)?" }, "Exclude Art Source Folders": { - "pattern": ".*\\\\/ArtSource\\\\/.*" + "pattern": "(^|[^/]+/)ArtSource(/.*)?" }, //------------------------------------------------------------------------------ // Copying Files Automatically Into the Cache From 41441b85a761361dfcb9dfdc381a8ffa9db64270 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 26 Oct 2021 11:54:41 -0500 Subject: [PATCH 069/200] =?UTF-8?q?Fixed=20Procedural=20Prefab=20asset=20o?= =?UTF-8?q?utput=20to=20set=20Source=20field=20to=20the=20corre=E2=80=A6?= =?UTF-8?q?=20(#4921)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed Procedural Prefab asset output to set Source field to the correct value (Relative path with filename and extension) Removed unneeded calculation of relative path for the output file since the AP handles that already Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Remove outdated comment Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Try to fix missing include Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Signed-off-by: Gene Walters --- .../PrefabGroup/PrefabGroupBehavior.cpp | 35 ++++++++----------- .../PrefabGroup/PrefabGroupBehavior.h | 3 +- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp index 3bc8e9bff9..af2a54f7a5 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.cpp @@ -81,7 +81,7 @@ namespace AZ::SceneAPI::Behaviors m_exportEventHandler.reset(); } - AZStd::unique_ptr PrefabGroupBehavior::CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup) const + AZStd::unique_ptr PrefabGroupBehavior::CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup, const AZ::IO::Path& relativePath) const { using namespace AzToolsFramework::Prefab; @@ -109,8 +109,12 @@ namespace AZ::SceneAPI::Behaviors return {}; } - // validate the PrefabDom will make a valid Prefab template instance - auto templateId = prefabLoaderInterface->LoadTemplateFromString(sb.GetString(), prefabGroup->GetName().c_str()); + // The originPath we pass to LoadTemplateFromString must be the relative path of the file + AZ::IO::Path templateName(prefabGroup->GetName()); + templateName.ReplaceExtension(AZ::Prefab::PrefabGroupAssetHandler::s_Extension); + templateName = relativePath / templateName; + + auto templateId = prefabLoaderInterface->LoadTemplateFromString(sb.GetString(), templateName.Native().c_str()); if (templateId == InvalidTemplateId) { AZ_Error("prefab", false, "PrefabGroup(%s) Could not write load template", prefabGroup->GetName().c_str()); @@ -136,22 +140,8 @@ namespace AZ::SceneAPI::Behaviors const SceneData::PrefabGroup* prefabGroup, const rapidjson::Document& doc) const { - // Retrieve source asset info so we can get a string with the relative path to the asset - bool assetInfoResult; - Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - assetInfoResult, - &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - context.GetScene().GetSourceFilename().c_str(), - info, - watchFolder); - - AZ::IO::FixedMaxPath assetPath(info.m_relativePath); - assetPath.ReplaceFilename(prefabGroup->GetName().c_str()); - AZStd::string filePath = AZ::SceneAPI::Utilities::FileUtilities::CreateOutputFileName( - assetPath.c_str(), + prefabGroup->GetName().c_str(), context.GetOutputDirectory(), AZ::Prefab::PrefabGroupAssetHandler::s_Extension); @@ -174,7 +164,7 @@ namespace AZ::SceneAPI::Behaviors const auto bytesWritten = fileStream.Write(sb.GetSize(), sb.GetString()); if (bytesWritten > 1) { - AZ::u32 subId = AZ::Crc32(assetPath.c_str()); + AZ::u32 subId = AZ::Crc32(prefabGroup->GetName().c_str()); context.GetProductList().AddProduct( filePath, context.GetScene().GetSourceGuid(), @@ -206,9 +196,14 @@ namespace AZ::SceneAPI::Behaviors return AZ::SceneAPI::Events::ProcessingResult::Ignored; } + // Get the relative path of the source and then take just the path portion of it (no file name) + AZ::IO::Path relativePath = context.GetScene().GetSourceFilename(); + relativePath = relativePath.LexicallyRelative(AZStd::string_view(context.GetScene().GetWatchFolder())); + relativePath = relativePath.ParentPath(); + for (const auto* prefabGroup : prefabGroupCollection) { - auto result = CreateProductAssetData(prefabGroup); + auto result = CreateProductAssetData(prefabGroup, relativePath); if (!result) { return Events::ProcessingResult::Failure; diff --git a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h index b57d30695a..5e787c316b 100644 --- a/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h +++ b/Gems/Prefab/PrefabBuilder/PrefabGroup/PrefabGroupBehavior.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ namespace AZ::SceneAPI::Behaviors private: Events::ProcessingResult OnPrepareForExport(Events::PreExportEventContext& context) const; - AZStd::unique_ptr CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup) const; + AZStd::unique_ptr CreateProductAssetData(const SceneData::PrefabGroup* prefabGroup, const AZ::IO::Path& relativePath) const; bool WriteOutProductAsset( Events::PreExportEventContext& context, From 7086cc912312d65360013d4e6edccea1d1e8954e Mon Sep 17 00:00:00 2001 From: puvvadar Date: Thu, 21 Oct 2021 14:36:51 -0700 Subject: [PATCH 070/200] Fix usages of AZStd::bitset not being found by serialize context Signed-off-by: puvvadar Signed-off-by: Gene Walters --- .../AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h | 3 ++- .../Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h index c85c45dd3e..5a57fa1e72 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h @@ -10,12 +10,13 @@ #pragma once #include +#include +#include #include #include #include #include #include -#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h index 74826d9f24..6dbfaaa948 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include From 957d2b36be2b274d26327a88d727e3342e813069 Mon Sep 17 00:00:00 2001 From: puvvadar Date: Fri, 22 Oct 2021 11:26:12 -0700 Subject: [PATCH 071/200] Add SerializeContext include for nounity builds Signed-off-by: puvvadar Signed-off-by: Gene Walters --- .../RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h index 6dbfaaa948..e7a0672931 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantKey.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include From 12784c4ada5469fa3642760bfea66cd6519d6b2e Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 22 Oct 2021 16:17:49 -0700 Subject: [PATCH 072/200] test cleanup and adding AtomComponentProperties Signed-off-by: Scott Murray Signed-off-by: Gene Walters --- .../Atom/TestSuite_Main_Optimized.py | 44 +++--- .../hydra_AtomEditorComponents_DecalAdded.py | 108 ++++++++----- ..._AtomEditorComponents_DepthOfFieldAdded.py | 129 ++++++++++------ ...mEditorComponents_DirectionalLightAdded.py | 112 +++++++++----- ...AtomEditorComponents_DisplayMapperAdded.py | 92 +++++++---- ...omEditorComponents_ExposureControlAdded.py | 145 ++++++++++++------ ...EditorComponents_GlobalSkylightIBLAdded.py | 117 ++++++++------ .../hydra_AtomEditorComponents_LightAdded.py | 87 +++++++---- ...ydra_AtomEditorComponents_MaterialAdded.py | 20 ++- .../hydra_AtomEditorComponents_MeshAdded.py | 12 +- ...a_AtomEditorComponents_PhysicalSkyAdded.py | 91 +++++++---- ...nents_PostFXGradientWeightModifierAdded.py | 16 +- ...a_AtomEditorComponents_PostFXLayerAdded.py | 10 +- ...ponents_PostFXRadiusWeightModifierAdded.py | 130 ++++++++++------ ...mponents_PostFxShapeWeightModifierAdded.py | 18 +-- ...omEditorComponents_ReflectionProbeAdded.py | 48 +++--- 16 files changed, 740 insertions(+), 439 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index c29a391be4..69a0e9c85d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -26,6 +26,10 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module + @pytest.mark.test_case_id("C36525660") + class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module + @pytest.mark.test_case_id("C32078121") class AtomEditorComponents_ExposureControlAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module @@ -34,46 +38,42 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module - @pytest.mark.test_case_id("C32078125") - class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module - - @pytest.mark.test_case_id("C32078131") - class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest): - from Atom.tests import ( - hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module) - @pytest.mark.test_case_id("C32078117") class AtomEditorComponents_LightAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module - @pytest.mark.test_case_id("C36525660") - class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module - - @pytest.mark.test_case_id("C32078128") - class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module + @pytest.mark.test_case_id("C32078123") + class AtomEditorComponents_MaterialAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module @pytest.mark.test_case_id("C32078124") class AtomEditorComponents_MeshAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module - @pytest.mark.test_case_id("C32078123") - class AtomEditorComponents_MaterialAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module + @pytest.mark.test_case_id("C32078125") + class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module + + @pytest.mark.test_case_id("C36525664") + class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module @pytest.mark.test_case_id("C32078127") class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module + @pytest.mark.test_case_id("C32078131") + class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest): + from Atom.tests import ( + hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module) + @pytest.mark.test_case_id("C36525665") class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module - @pytest.mark.test_case_id("C36525664") - class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module + @pytest.mark.test_case_id("C32078128") + class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py index fa02b75fe2..e840cf3cf1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py @@ -5,25 +5,52 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - decal_creation = ("Decal Entity successfully created", "Decal Entity failed to be created") - decal_component = ("Entity has a Decal component", "Entity failed to find Decal component") - material_property_set = ("Material property set on Decal component", "Couldn't set Material property on Decal component") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + decal_creation = ( + "Decal Entity successfully created", + "Decal Entity failed to be created") + decal_component = ( + "Entity has a Decal component", + "Entity failed to find Decal component") + material_property_set = ( + "Material property set on Decal component", + "Couldn't set Material property on Decal component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_Decal_AddedToEntity(): @@ -51,35 +78,33 @@ def AtomEditorComponents_Decal_AddedToEntity(): 9) Delete Decal entity. 10) UNDO deletion. 11) REDO deletion. - 12) Look for errors. + 12) Look for errors and asserts. :return: None """ import os - import azlmbr.asset as asset - import azlmbr.bus as bus import azlmbr.legacy.general as general - import azlmbr.math as math + from editor_python_test_tools.asset_utils import Asset from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Decal entity with no components. - decal_name = "Decal" - decal_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), decal_name) + decal_entity = EditorEntity.create_editor_entity(AtomComponentProperties.decal()) Report.critical_result(Tests.decal_creation, decal_entity.exists()) # 2. Add Decal component to Decal entity. - decal_component = decal_entity.add_component(decal_name) - Report.critical_result(Tests.decal_component, decal_entity.has_component(decal_name)) + decal_component = decal_entity.add_component(AtomComponentProperties.decal()) + Report.critical_result(Tests.decal_component, decal_entity.has_component(AtomComponentProperties.decal())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -106,9 +131,9 @@ def AtomEditorComponents_Decal_AddedToEntity(): Report.result(Tests.creation_redo, decal_entity.exists()) # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 6. Test IsHidden. decal_entity.set_visibility_state(False) @@ -120,13 +145,11 @@ def AtomEditorComponents_Decal_AddedToEntity(): Report.result(Tests.is_visible, decal_entity.is_visible() is True) # 8. Set Material property on Decal component. - decal_material_property_path = "Controller|Configuration|Material" - decal_material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material") - decal_material_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", decal_material_asset_path, math.Uuid(), False) - decal_component.set_component_property_value(decal_material_property_path, decal_material_asset) - get_material_property = decal_component.get_component_property_value(decal_material_property_path) - Report.result(Tests.material_property_set, get_material_property == decal_material_asset) + decal_material_asset_path = os.path.join("materials", "basic_grey.azmaterial") + decal_material_asset = Asset.find_asset_by_path(decal_material_asset_path, False) + decal_component.set_component_property_value(AtomComponentProperties.decal('Material'), decal_material_asset.id) + get_material_property = decal_component.get_component_property_value(AtomComponentProperties.decal('Material')) + Report.result(Tests.material_property_set, get_material_property == decal_material_asset.id) # 9. Delete Decal entity. decal_entity.delete() @@ -141,9 +164,12 @@ def AtomEditorComponents_Decal_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not decal_entity.exists()) - # 12. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 12. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py index 80284902ea..e2c5f9c77d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py @@ -5,28 +5,61 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to Camera entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - camera_property_set = ("DepthOfField Entity set Camera Entity", "DepthOfField Entity could not set Camera Entity") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - depth_of_field_creation = ("DepthOfField Entity successfully created", "DepthOfField Entity failed to be created") - depth_of_field_component = ("Entity has a DepthOfField component", "Entity failed to find DepthOfField component") - depth_of_field_disabled = ("DepthOfField component disabled", "DepthOfField component was not disabled.") - post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component") - depth_of_field_enabled = ("DepthOfField component enabled", "DepthOfField component was not enabled.") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to Camera entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + camera_property_set = ( + "DepthOfField Entity set Camera Entity", + "DepthOfField Entity could not set Camera Entity") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + depth_of_field_creation = ( + "DepthOfField Entity successfully created", + "DepthOfField Entity failed to be created") + depth_of_field_component = ( + "Entity has a DepthOfField component", + "Entity failed to find DepthOfField component") + depth_of_field_disabled = ( + "DepthOfField component disabled", + "DepthOfField component was not disabled.") + post_fx_component = ( + "Entity has a Post FX Layer component", + "Entity did not have a Post FX Layer component") + depth_of_field_enabled = ( + "DepthOfField component enabled", + "DepthOfField component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_DepthOfField_AddedToEntity(): @@ -59,33 +92,32 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): 14) Delete DepthOfField entity. 15) UNDO deletion. 16) REDO deletion. - 17) Look for errors. + 17) Look for errors and asserts. :return: None """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a DepthOfField entity with no components. - depth_of_field_name = "DepthOfField" - depth_of_field_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), depth_of_field_name) + depth_of_field_entity = EditorEntity.create_editor_entity(AtomComponentProperties.depth_of_field()) Report.critical_result(Tests.depth_of_field_creation, depth_of_field_entity.exists()) # 2. Add a DepthOfField component to DepthOfField entity. - depth_of_field_component = depth_of_field_entity.add_component(depth_of_field_name) - Report.critical_result(Tests.depth_of_field_component, depth_of_field_entity.has_component(depth_of_field_name)) + depth_of_field_component = depth_of_field_entity.add_component(AtomComponentProperties.depth_of_field()) + Report.critical_result(Tests.depth_of_field_component, + depth_of_field_entity.has_component(AtomComponentProperties.depth_of_field())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -115,17 +147,16 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): Report.result(Tests.depth_of_field_disabled, not depth_of_field_component.is_enabled()) # 6. Add Post FX Layer component since it is required by the DepthOfField component. - post_fx_layer = "PostFX Layer" - depth_of_field_entity.add_component(post_fx_layer) - Report.result(Tests.post_fx_component, depth_of_field_entity.has_component(post_fx_layer)) + depth_of_field_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result(Tests.post_fx_component, depth_of_field_entity.has_component(AtomComponentProperties.postfx_layer())) # 7. Verify DepthOfField component is enabled. Report.result(Tests.depth_of_field_enabled, depth_of_field_component.is_enabled()) # 8. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 9. Test IsHidden. depth_of_field_entity.set_visibility_state(False) @@ -137,19 +168,20 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): Report.result(Tests.is_visible, depth_of_field_entity.is_visible() is True) # 11. Add Camera entity. - camera_name = "Camera" - camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name) + camera_entity = EditorEntity.create_editor_entity(AtomComponentProperties.camera()) Report.result(Tests.camera_creation, camera_entity.exists()) # 12. Add Camera component to Camera entity. - camera_entity.add_component(camera_name) - Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name)) + camera_entity.add_component(AtomComponentProperties.camera()) + Report.result(Tests.camera_component_added, camera_entity.has_component(AtomComponentProperties.camera())) # 13. Set the DepthOfField components's Camera Entity to the newly created Camera entity. - depth_of_field_camera_property_path = "Controller|Configuration|Camera Entity" - depth_of_field_component.set_component_property_value(depth_of_field_camera_property_path, camera_entity.id) - camera_entity_set = depth_of_field_component.get_component_property_value(depth_of_field_camera_property_path) - Report.result(Tests.camera_property_set, camera_entity.id == camera_entity_set) + depth_of_field_component.set_component_property_value( + AtomComponentProperties.depth_of_field('Camera Entity'), camera_entity.id) + Report.result( + Tests.camera_property_set, + camera_entity.id == depth_of_field_component.get_component_property_value( + AtomComponentProperties.depth_of_field('Camera Entity'))) # 14. Delete DepthOfField entity. depth_of_field_entity.delete() @@ -163,9 +195,12 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not depth_of_field_entity.exists()) - # 17. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 17. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py index 048e132df4..f3ffc0f366 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py @@ -5,25 +5,52 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - directional_light_creation = ("Directional Light Entity successfully created", "Directional Light Entity failed to be created") - directional_light_component = ("Entity has a Directional Light component", "Entity failed to find Directional Light component") - shadow_camera_check = ("Directional Light component Shadow camera set", "Directional Light component Shadow camera was not set") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + directional_light_creation = ( + "Directional Light Entity successfully created", + "Directional Light Entity failed to be created") + directional_light_component = ( + "Entity has a Directional Light component", + "Entity failed to find Directional Light component") + shadow_camera_check = ( + "Directional Light component Shadow camera set", + "Directional Light component Shadow camera was not set") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_DirectionalLight_AddedToEntity(): @@ -53,34 +80,33 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): 11) Delete Directional Light entity. 12) UNDO deletion. 13) REDO deletion. - 14) Look for errors. + 14) Look for errors and asserts. :return: None """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Directional Light entity with no components. - directional_light_name = "Directional Light" - directional_light_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), directional_light_name) + directional_light_entity = EditorEntity.create_editor_entity(AtomComponentProperties.directional_light()) Report.critical_result(Tests.directional_light_creation, directional_light_entity.exists()) # 2. Add Directional Light component to Directional Light entity. - directional_light_component = directional_light_entity.add_component(directional_light_name) + directional_light_component = directional_light_entity.add_component(AtomComponentProperties.directional_light()) Report.critical_result( - Tests.directional_light_component, directional_light_entity.has_component(directional_light_name)) + Tests.directional_light_component, + directional_light_entity.has_component(AtomComponentProperties.directional_light())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -107,9 +133,9 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): Report.result(Tests.creation_redo, directional_light_entity.exists()) # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 6. Test IsHidden. directional_light_entity.set_visibility_state(False) @@ -121,19 +147,20 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): Report.result(Tests.is_visible, directional_light_entity.is_visible() is True) # 8. Add Camera entity. - camera_name = "Camera" - camera_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), camera_name) + camera_entity = EditorEntity.create_editor_entity(AtomComponentProperties.camera()) Report.result(Tests.camera_creation, camera_entity.exists()) # 9. Add Camera component to Camera entity. - camera_entity.add_component(camera_name) - Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name)) + camera_entity.add_component(AtomComponentProperties.camera()) + Report.result(Tests.camera_component_added, camera_entity.has_component(AtomComponentProperties.camera())) # 10. Set the Directional Light component property Shadow|Camera to the Camera entity. - shadow_camera_property_path = "Controller|Configuration|Shadow|Camera" - directional_light_component.set_component_property_value(shadow_camera_property_path, camera_entity.id) - shadow_camera_set = directional_light_component.get_component_property_value(shadow_camera_property_path) - Report.result(Tests.shadow_camera_check, camera_entity.id == shadow_camera_set) + directional_light_component.set_component_property_value( + AtomComponentProperties.directional_light('Camera'), camera_entity.id) + Report.result( + Tests.shadow_camera_check, + camera_entity.id == directional_light_component.get_component_property_value( + AtomComponentProperties.directional_light('Camera'))) # 11. Delete DirectionalLight entity. directional_light_entity.delete() @@ -147,9 +174,12 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not directional_light_entity.exists()) - # 14. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 14. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py index 39d7acf4f4..f8881bfa2a 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py @@ -5,24 +5,49 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - display_mapper_creation = ("Display Mapper Entity successfully created", "Display Mapper Entity failed to be created") - display_mapper_component = ("Entity has a Display Mapper component", "Entity failed to find Display Mapper component") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + display_mapper_creation = ( + "Display Mapper Entity successfully created", + "Display Mapper Entity failed to be created") + display_mapper_component = ( + "Entity has a Display Mapper component", + "Entity failed to find Display Mapper component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_DisplayMapper_AddedToEntity(): @@ -49,33 +74,33 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): 8) Delete Display Mapper entity. 9) UNDO deletion. 10) REDO deletion. - 11) Look for errors. + 11) Look for errors and asserts. :return: None """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Display Mapper entity with no components. - display_mapper = "Display Mapper" - display_mapper_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), f"{display_mapper}") + display_mapper_entity = EditorEntity.create_editor_entity(AtomComponentProperties.display_mapper()) Report.critical_result(Tests.display_mapper_creation, display_mapper_entity.exists()) # 2. Add Display Mapper component to Display Mapper entity. - display_mapper_entity.add_component(display_mapper) - Report.critical_result(Tests.display_mapper_component, display_mapper_entity.has_component(display_mapper)) + display_mapper_entity.add_component(AtomComponentProperties.display_mapper()) + Report.critical_result( + Tests.display_mapper_component, + display_mapper_entity.has_component(AtomComponentProperties.display_mapper())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -102,9 +127,9 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): Report.result(Tests.creation_redo, display_mapper_entity.exists()) # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 6. Test IsHidden. display_mapper_entity.set_visibility_state(False) @@ -127,9 +152,12 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not display_mapper_entity.exists()) - # 11. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 11. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py index 23a84435f7..6fa9660539 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py @@ -5,25 +5,58 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - exposure_control_creation = ("ExposureControl Entity successfully created", "ExposureControl Entity failed to be created") - exposure_control_component = ("Entity has a Exposure Control component", "Entity failed to find Exposure Control component") - post_fx_component = ("Entity has a Post FX Layer component", "Entity did not have a Post FX Layer component") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + exposure_control_creation = ( + "ExposureControl Entity successfully created", + "ExposureControl Entity failed to be created") + exposure_control_component = ( + "Entity has a Exposure Control component", + "Entity failed to find Exposure Control component") + exposure_control_disabled = ( + "DepthOfField component disabled", + "DepthOfField component was not disabled.") + post_fx_component = ( + "Entity has a Post FX Layer component", + "Entity did not have a Post FX Layer component") + exposure_control_enabled = ( + "DepthOfField component enabled", + "DepthOfField component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_ExposureControl_AddedToEntity(): @@ -44,41 +77,42 @@ def AtomEditorComponents_ExposureControl_AddedToEntity(): 2) Add Exposure Control component to Exposure Control entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Add Post FX Layer component. - 9) Delete Exposure Control entity. - 10) UNDO deletion. - 11) REDO deletion. - 12) Look for errors. + 5) Verify Exposure Control component not enabled. + 6) Add Post FX Layer component since it is required by the Exposure Control component. + 7) Verify Exposure Control component is enabled. + 8) Enter/Exit game mode. + 9) Test IsHidden. + 10) Test IsVisible. + 11) Delete Exposure Control entity. + 12) UNDO deletion. + 13) REDO deletion. + 14) Look for errors and asserts. :return: None """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Creation of Exposure Control entity with no components. - exposure_control_name = "Exposure Control" - exposure_control_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), f"{exposure_control_name}") + exposure_control_entity = EditorEntity.create_editor_entity(AtomComponentProperties.exposure_control()) Report.critical_result(Tests.exposure_control_creation, exposure_control_entity.exists()) # 2. Add Exposure Control component to Exposure Control entity. - exposure_control_entity.add_component(exposure_control_name) + exposure_control_component = exposure_control_entity.add_component(AtomComponentProperties.exposure_control()) Report.critical_result( - Tests.exposure_control_component, exposure_control_entity.has_component(exposure_control_name)) + Tests.exposure_control_component, + exposure_control_entity.has_component(AtomComponentProperties.exposure_control())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -104,40 +138,49 @@ def AtomEditorComponents_ExposureControl_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, exposure_control_entity.exists()) - # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + # 5. Verify Exposure Control component not enabled. + Report.result(Tests.exposure_control_disabled, not exposure_control_component.is_enabled()) + + # 6. Add Post FX Layer component since it is required by the Exposure Control component. + exposure_control_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result(Tests.post_fx_component, + exposure_control_entity.has_component(AtomComponentProperties.postfx_layer())) + + # 7. Verify Exposure Control component is enabled. + Report.result(Tests.exposure_control_enabled, exposure_control_component.is_enabled()) + + # 8. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) - # 6. Test IsHidden. + # 9. Test IsHidden. exposure_control_entity.set_visibility_state(False) Report.result(Tests.is_hidden, exposure_control_entity.is_hidden() is True) - # 7. Test IsVisible. + # 10. Test IsVisible. exposure_control_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, exposure_control_entity.is_visible() is True) - # 8. Add Post FX Layer component. - post_fx_layer_name = "PostFX Layer" - exposure_control_entity.add_component(post_fx_layer_name) - Report.result(Tests.post_fx_component, exposure_control_entity.has_component(post_fx_layer_name)) - - # 9. Delete ExposureControl entity. + # 11. Delete ExposureControl entity. exposure_control_entity.delete() Report.result(Tests.entity_deleted, not exposure_control_entity.exists()) - # 10. UNDO deletion. + # 12. UNDO deletion. general.undo() Report.result(Tests.deletion_undo, exposure_control_entity.exists()) - # 11. REDO deletion. + # 13. REDO deletion. general.redo() Report.result(Tests.deletion_redo, not exposure_control_entity.exists()) - # 12. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 14. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py index cc891f5929..db8f2daaee 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py @@ -5,26 +5,55 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - global_skylight_creation = ("Global Skylight (IBL) Entity successfully created", "Global Skylight (IBL) Entity failed to be created") - global_skylight_component = ("Entity has a Global Skylight (IBL) component", "Entity failed to find Global Skylight (IBL) component") - diffuse_image_set = ("Entity has the Diffuse Image set", "Entity did not the Diffuse Image set") - specular_image_set = ("Entity has the Specular Image set", "Entity did not the Specular Image set") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + global_skylight_creation = ( + "Global Skylight (IBL) Entity successfully created", + "Global Skylight (IBL) Entity failed to be created") + global_skylight_component = ( + "Entity has a Global Skylight (IBL) component", + "Entity failed to find Global Skylight (IBL) component") + diffuse_image_set = ( + "Entity has the Diffuse Image set", + "Entity did not the Diffuse Image set") + specular_image_set = ( + "Entity has the Specular Image set", + "Entity did not the Specular Image set") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): @@ -60,29 +89,28 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): import os import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.asset_utils import Asset from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Global Skylight (IBL) entity with no components. - global_skylight_name = "Global Skylight (IBL)" - global_skylight_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), global_skylight_name) + global_skylight_entity = EditorEntity.create_editor_entity(AtomComponentProperties.global_skylight()) Report.critical_result(Tests.global_skylight_creation, global_skylight_entity.exists()) # 2. Add Global Skylight (IBL) component to Global Skylight (IBL) entity. - global_skylight_component = global_skylight_entity.add_component(global_skylight_name) + global_skylight_component = global_skylight_entity.add_component(AtomComponentProperties.global_skylight()) Report.critical_result( - Tests.global_skylight_component, global_skylight_entity.has_component(global_skylight_name)) + Tests.global_skylight_component, + global_skylight_entity.has_component(AtomComponentProperties.global_skylight())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -109,9 +137,9 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): Report.result(Tests.creation_redo, global_skylight_entity.exists()) # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 6. Test IsHidden. global_skylight_entity.set_visibility_state(False) @@ -123,24 +151,24 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): Report.result(Tests.is_visible, global_skylight_entity.is_visible() is True) # 8. Set the Diffuse Image asset on the Global Skylight (IBL) entity. - global_skylight_diffuse_image_property = "Controller|Configuration|Diffuse Image" diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage") diffuse_image_asset = Asset.find_asset_by_path(diffuse_image_path, False) global_skylight_component.set_component_property_value( - global_skylight_diffuse_image_property, diffuse_image_asset.id) - diffuse_image_set = global_skylight_component.get_component_property_value( - global_skylight_diffuse_image_property) - Report.result(Tests.diffuse_image_set, diffuse_image_set == diffuse_image_asset.id) + AtomComponentProperties.global_skylight('Diffuse Image'), diffuse_image_asset.id) + Report.result( + Tests.diffuse_image_set, + diffuse_image_asset.id == global_skylight_component.get_component_property_value( + AtomComponentProperties.global_skylight('Diffuse Image'))) # 9. Set the Specular Image asset on the Global Light (IBL) entity. - global_skylight_specular_image_property = "Controller|Configuration|Specular Image" specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage") specular_image_asset = Asset.find_asset_by_path(specular_image_path, False) global_skylight_component.set_component_property_value( - global_skylight_specular_image_property, specular_image_asset.id) - specular_image_added = global_skylight_component.get_component_property_value( - global_skylight_specular_image_property) - Report.result(Tests.specular_image_set, specular_image_added == specular_image_asset.id) + AtomComponentProperties.global_skylight('Specular Image'), specular_image_asset.id) + Report.result( + Tests.specular_image_set, + specular_image_asset.id == global_skylight_component.get_component_property_value( + AtomComponentProperties.global_skylight('Specular Image'))) # 10. Delete Global Skylight (IBL) entity. global_skylight_entity.delete() @@ -154,9 +182,12 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not global_skylight_entity.exists()) - # 13. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 13. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py index 8b1432f1f7..249671556d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py @@ -5,24 +5,49 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - light_creation = ("Light Entity successfully created", "Light Entity failed to be created") - light_component = ("Entity has a Light component", "Entity failed to find Light component") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + light_creation = ( + "Light Entity successfully created", + "Light Entity failed to be created") + light_component = ( + "Entity has a Light component", + "Entity failed to find Light component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_Light_AddedToEntity(): @@ -55,26 +80,25 @@ def AtomEditorComponents_Light_AddedToEntity(): """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Light entity with no components. - light_name = "Light" - light_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), light_name) + light_entity = EditorEntity.create_editor_entity(AtomComponentProperties.light()) Report.critical_result(Tests.light_creation, light_entity.exists()) # 2. Add Light component to the Light entity. - light_entity.add_component(light_name) - Report.critical_result(Tests.light_component, light_entity.has_component(light_name)) + light_component = light_entity.add_component(AtomComponentProperties.light()) + Report.critical_result(Tests.light_component, light_entity.has_component(AtomComponentProperties.light())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -101,9 +125,9 @@ def AtomEditorComponents_Light_AddedToEntity(): Report.result(Tests.creation_redo, light_entity.exists()) # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 6. Test IsHidden. light_entity.set_visibility_state(False) @@ -126,9 +150,12 @@ def AtomEditorComponents_Light_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not light_entity.exists()) - # 11. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 11. Look for errors asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py index 32cd5471f2..c613bb23e7 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py @@ -96,6 +96,7 @@ def AtomEditorComponents_Material_AddedToEntity(): from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. @@ -105,15 +106,14 @@ def AtomEditorComponents_Material_AddedToEntity(): # Test steps begin. # 1. Create a Material entity with no components. - material_name = "Material" - material_entity = EditorEntity.create_editor_entity(material_name) + material_entity = EditorEntity.create_editor_entity(AtomComponentProperties.material()) Report.critical_result(Tests.material_creation, material_entity.exists()) # 2. Add a Material component to Material entity. - material_component = material_entity.add_component(material_name) + material_component = material_entity.add_component(AtomComponentProperties.material()) Report.critical_result( Tests.material_component, - material_entity.has_component(material_name)) + material_entity.has_component(AtomComponentProperties.material())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -143,9 +143,8 @@ def AtomEditorComponents_Material_AddedToEntity(): Report.result(Tests.material_disabled, not material_component.is_enabled()) # 6. Add Actor component since it is required by the Material component. - actor_name = "Actor" - material_entity.add_component(actor_name) - Report.result(Tests.actor_component, material_entity.has_component(actor_name)) + material_entity.add_component(AtomComponentProperties.actor()) + Report.result(Tests.actor_component, material_entity.has_component(AtomComponentProperties.actor())) # 7. Verify Material component is enabled. Report.result(Tests.material_enabled, material_component.is_enabled()) @@ -153,15 +152,14 @@ def AtomEditorComponents_Material_AddedToEntity(): # 8. UNDO component addition. general.undo() general.idle_wait_frames(1) - Report.result(Tests.actor_undo, not material_entity.has_component(actor_name)) + Report.result(Tests.actor_undo, not material_entity.has_component(AtomComponentProperties.actor())) # 9. Verify Material component not enabled. Report.result(Tests.material_disabled, not material_component.is_enabled()) # 10. Add Mesh component since it is required by the Material component. - mesh_name = "Mesh" - material_entity.add_component(mesh_name) - Report.result(Tests.mesh_component, material_entity.has_component(mesh_name)) + material_entity.add_component(AtomComponentProperties.mesh()) + Report.result(Tests.mesh_component, material_entity.has_component(AtomComponentProperties.mesh())) # 11. Verify Material component is enabled. Report.result(Tests.material_enabled, material_component.is_enabled()) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py index 82d3b89309..9d56753961 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py @@ -81,7 +81,7 @@ def AtomEditorComponents_Mesh_AddedToEntity(): from editor_python_test_tools.asset_utils import Asset from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper - from Atom.atom_utils.atom_constants import AtomComponentProperties as Atom + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. @@ -91,14 +91,14 @@ def AtomEditorComponents_Mesh_AddedToEntity(): # Test steps begin. # 1. Create a Mesh entity with no components. - mesh_entity = EditorEntity.create_editor_entity(Atom.mesh()) + mesh_entity = EditorEntity.create_editor_entity(AtomComponentProperties.mesh()) Report.critical_result(Tests.mesh_entity_creation, mesh_entity.exists()) # 2. Add a Mesh component to Mesh entity. - mesh_component = mesh_entity.add_component(Atom.mesh()) + mesh_component = mesh_entity.add_component(AtomComponentProperties.mesh()) Report.critical_result( Tests.mesh_component_added, - mesh_entity.has_component(Atom.mesh())) + mesh_entity.has_component(AtomComponentProperties.mesh())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -127,9 +127,9 @@ def AtomEditorComponents_Mesh_AddedToEntity(): # 5. Set Mesh component asset property model_path = os.path.join('Objects', 'shaderball', 'shaderball_default_1m.azmodel') model = Asset.find_asset_by_path(model_path) - mesh_component.set_component_property_value(Atom.mesh('Mesh Asset'), model.id) + mesh_component.set_component_property_value(AtomComponentProperties.mesh('Mesh Asset'), model.id) Report.result(Tests.mesh_asset_specified, - mesh_component.get_component_property_value(Atom.mesh('Mesh Asset')) == model.id) + mesh_component.get_component_property_value(AtomComponentProperties.mesh('Mesh Asset')) == model.id) # 6. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py index 04441d5b2c..fa8c626016 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py @@ -5,24 +5,49 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - physical_sky_creation = ("Physical Sky Entity successfully created", "Physical Sky Entity failed to be created") - physical_sky_component = ("Entity has a Physical Sky component", "Entity failed to find Physical Sky component") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + camera_creation = ( + "Camera Entity successfully created", + "Camera Entity failed to be created") + camera_component_added = ( + "Camera component was added to entity", + "Camera component failed to be added to entity") + camera_component_check = ( + "Entity has a Camera component", + "Entity failed to find Camera component") + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + physical_sky_creation = ( + "Physical Sky Entity successfully created", + "Physical Sky Entity failed to be created") + physical_sky_component = ( + "Entity has a Physical Sky component", + "Entity failed to find Physical Sky component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_PhysicalSky_AddedToEntity(): @@ -49,32 +74,33 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): 8) Delete Physical Sky entity. 9) UNDO deletion. 10) REDO deletion. - 11) Look for errors. + 11) Look for errors and asserts. :return: None """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Physical Sky entity with no components. - physical_sky_name = "Physical Sky" - physical_sky_entity = EditorEntity.create_editor_entity_at(math.Vector3(512.0, 512.0, 34.0), physical_sky_name) + physical_sky_entity = EditorEntity.create_editor_entity(AtomComponentProperties.physical_sky()) Report.critical_result(Tests.physical_sky_creation, physical_sky_entity.exists()) # 2. Add Physical Sky component to Physical Sky entity. - physical_sky_entity.add_component(physical_sky_name) - Report.critical_result(Tests.physical_sky_component, physical_sky_entity.has_component(physical_sky_name)) + physical_sky_component = physical_sky_entity.add_component(AtomComponentProperties.physical_sky()) + Report.critical_result( + Tests.physical_sky_component, + physical_sky_entity.has_component(AtomComponentProperties.physical_sky())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -101,9 +127,9 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): Report.result(Tests.creation_redo, physical_sky_entity.exists()) # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 6. Test IsHidden. physical_sky_entity.set_visibility_state(False) @@ -126,9 +152,12 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): general.redo() Report.result(Tests.deletion_redo, not physical_sky_entity.exists()) - # 11. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 11. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py index d38e96739d..6e4ae2d9ac 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py @@ -86,6 +86,7 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. @@ -95,15 +96,15 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): # Test steps begin. # 1. Create a PostFX Gradient Weight Modifier entity with no components. - postfx_gradient_weight_name = "PostFX Gradient Weight Modifier" - postfx_gradient_weight_entity = EditorEntity.create_editor_entity(postfx_gradient_weight_name) + postfx_gradient_weight_entity = EditorEntity.create_editor_entity(AtomComponentProperties.postfx_gradient()) Report.critical_result(Tests.postfx_gradient_weight_creation, postfx_gradient_weight_entity.exists()) # 2. Add a PostFX Gradient Weight Modifier component to PostFX Gradient Weight Modifier entity. - postfx_gradient_weight_component = postfx_gradient_weight_entity.add_component(postfx_gradient_weight_name) + postfx_gradient_weight_component = postfx_gradient_weight_entity.add_component( + AtomComponentProperties.postfx_gradient()) Report.critical_result( Tests.postfx_gradient_weight_component, - postfx_gradient_weight_entity.has_component(postfx_gradient_weight_name)) + postfx_gradient_weight_entity.has_component(AtomComponentProperties.postfx_gradient())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -133,9 +134,10 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): Report.result(Tests.postfx_gradient_weight_disabled, not postfx_gradient_weight_component.is_enabled()) # 6. Add PostFX Layer component since it is required by the PostFX Gradient Weight Modifier component. - postfx_layer_name = "PostFX Layer" - postfx_gradient_weight_entity.add_component(postfx_layer_name) - Report.result(Tests.postfx_layer_component, postfx_gradient_weight_entity.has_component(postfx_layer_name)) + postfx_gradient_weight_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result( + Tests.postfx_layer_component, + postfx_gradient_weight_entity.has_component(AtomComponentProperties.postfx_layer())) # 7. Verify PostFX Gradient Weight Modifier component is enabled. Report.result(Tests.postfx_gradient_weight_enabled, postfx_gradient_weight_component.is_enabled()) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py index 8c2dee416b..a81864f379 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py @@ -76,6 +76,7 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. @@ -85,13 +86,14 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): # Test steps begin. # 1. Create a PostFX Layer entity with no components. - postfx_layer_name = "PostFX Layer" - postfx_layer_entity = EditorEntity.create_editor_entity(postfx_layer_name) + postfx_layer_entity = EditorEntity.create_editor_entity(AtomComponentProperties.postfx_layer()) Report.critical_result(Tests.postfx_layer_entity_creation, postfx_layer_entity.exists()) # 2. Add a PostFX Layer component to PostFX Layer entity. - postfx_layer_component = postfx_layer_entity.add_component(postfx_layer_name) - Report.critical_result(Tests.postfx_layer_component_added, postfx_layer_entity.has_component(postfx_layer_name)) + postfx_layer_component = postfx_layer_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.critical_result( + Tests.postfx_layer_component_added, + postfx_layer_entity.has_component(AtomComponentProperties.postfx_layer())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py index 8914ab9e7e..228ddfcdc5 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py @@ -5,24 +5,49 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -# fmt: off class Tests: - camera_creation = ("Camera Entity successfully created", "Camera Entity failed to be created") - camera_component_added = ("Camera component was added to entity", "Camera component failed to be added to entity") - camera_component_check = ("Entity has a Camera component", "Entity failed to find Camera component") - creation_undo = ("UNDO Entity creation success", "UNDO Entity creation failed") - creation_redo = ("REDO Entity creation success", "REDO Entity creation failed") - postfx_radius_weight_creation = ("PostFX Radius Weight Modifier Entity successfully created", "PostFX Radius Weight Modifier Entity failed to be created") - postfx_radius_weight_component = ("Entity has a PostFX Radius Weight Modifier component", "Entity failed to find PostFX Radius Weight Modifier component") - enter_game_mode = ("Entered game mode", "Failed to enter game mode") - exit_game_mode = ("Exited game mode", "Couldn't exit game mode") - is_visible = ("Entity is visible", "Entity was not visible") - is_hidden = ("Entity is hidden", "Entity was not hidden") - entity_deleted = ("Entity deleted", "Entity was not deleted") - deletion_undo = ("UNDO deletion success", "UNDO deletion failed") - deletion_redo = ("REDO deletion success", "REDO deletion failed") - no_error_occurred = ("No errors detected", "Errors were detected") -# fmt: on + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + postfx_radius_weight_creation = ( + "PostFX Radius Weight Modifier Entity successfully created", + "PostFX Radius Weight Modifier Entity failed to be created") + postfx_radius_weight_component = ( + "Entity has a PostFX Radius Weight Modifier component", + "Entity failed to find PostFX Radius Weight Modifier component") + postfx_radius_weight_disabled = ( + "PostFX Radius Weight Modifier component disabled", + "PostFX Radius Weight Modifier component was not disabled.") + postfx_layer_component = ( + "Entity has a PostFX Layer component", + "Entity did not have an PostFX Layer component") + postfx_radius_weight_enabled = ( + "PostFX Radius Weight Modifier component enabled", + "PostFX Radius Weight Modifier component was not enabled.") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): @@ -43,40 +68,42 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): 2) Add Post FX Radius Weight Modifier component to Post FX Radius Weight Modifier entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Delete PostFX Radius Weight Modifier entity. - 9) UNDO deletion. - 10) REDO deletion. - 11) Look for errors. + 5) Verify PostFX Radius Weight Modifier component not enabled. + 6) Add PostFX Layer component since it is required by the PostFX Radius Weight Modifier component. + 7) Verify PostFX Radius Weight Modifier component is enabled. + 8) Enter/Exit game mode. + 9) Test IsHidden. + 10) Test IsVisible. + 11) Delete PostFX Radius Weight Modifier entity. + 12) UNDO deletion. + 13) REDO deletion. + 14) Look for errors. :return: None """ import azlmbr.legacy.general as general - import azlmbr.math as math from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Post FX Radius Weight Modifier entity with no components. - postfx_radius_weight_name = "PostFX Radius Weight Modifier" - postfx_radius_weight_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), postfx_radius_weight_name) + postfx_radius_weight_entity = EditorEntity.create_editor_entity(AtomComponentProperties.postfx_radius()) Report.critical_result(Tests.postfx_radius_weight_creation, postfx_radius_weight_entity.exists()) # 2. Add Post FX Radius Weight Modifier component to Post FX Radius Weight Modifier entity. - postfx_radius_weight_entity.add_component(postfx_radius_weight_name) + postfx_radius_component = postfx_radius_weight_entity.add_component(AtomComponentProperties.postfx_radius()) Report.critical_result( - Tests.postfx_radius_weight_component, postfx_radius_weight_entity.has_component(postfx_radius_weight_name)) + Tests.postfx_radius_weight_component, + postfx_radius_weight_entity.has_component(AtomComponentProperties.postfx_radius())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -102,35 +129,50 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, postfx_radius_weight_entity.exists()) - # 5. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + # 5. Verify PostFX Radius Weight Modifier component not enabled. + Report.result(Tests.postfx_radius_weight_disabled, not postfx_radius_component.is_enabled()) + + # 6. Add PostFX Layer component since it is required by the PostFX Radius Weight Modifier component. + postfx_radius_weight_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result( + Tests.postfx_layer_component, + postfx_radius_weight_entity.has_component(AtomComponentProperties.postfx_layer())) + + # 7. Verify PostFX Radius Weight Modifier component is enabled. + Report.result(Tests.postfx_radius_weight_enabled, postfx_radius_component.is_enabled()) + + # 8. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) - # 6. Test IsHidden. + # 9. Test IsHidden. postfx_radius_weight_entity.set_visibility_state(False) Report.result(Tests.is_hidden, postfx_radius_weight_entity.is_hidden() is True) - # 7. Test IsVisible. + # 10. Test IsVisible. postfx_radius_weight_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, postfx_radius_weight_entity.is_visible() is True) - # 8. Delete PostFX Radius Weight Modifier entity. + # 11. Delete PostFX Radius Weight Modifier entity. postfx_radius_weight_entity.delete() Report.result(Tests.entity_deleted, not postfx_radius_weight_entity.exists()) - # 9. UNDO deletion. + # 12. UNDO deletion. general.undo() Report.result(Tests.deletion_undo, postfx_radius_weight_entity.exists()) - # 10. REDO deletion. + # 13. REDO deletion. general.redo() Report.result(Tests.deletion_redo, not postfx_radius_weight_entity.exists()) - # 11. Look for errors. - helper.wait_for_condition(lambda: error_tracer.has_errors, 1.0) - Report.result(Tests.no_error_occurred, not error_tracer.has_errors) + # 14. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py index 4c98bcd130..0a37ac6bf7 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py @@ -92,6 +92,7 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. @@ -101,15 +102,14 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): # Test steps begin. # 1. Create a PostFx Shape Weight Modifier entity with no components. - postfx_shape_weight_name = "PostFX Shape Weight Modifier" - postfx_shape_weight_entity = EditorEntity.create_editor_entity(postfx_shape_weight_name) + postfx_shape_weight_entity = EditorEntity.create_editor_entity(AtomComponentProperties.postfx_shape()) Report.critical_result(Tests.postfx_shape_weight_creation, postfx_shape_weight_entity.exists()) # 2. Add a PostFx Shape Weight Modifier component to PostFx Shape Weight Modifier entity. - postfx_shape_weight_component = postfx_shape_weight_entity.add_component(postfx_shape_weight_name) + postfx_shape_weight_component = postfx_shape_weight_entity.add_component(AtomComponentProperties.postfx_shape()) Report.critical_result( Tests.postfx_shape_weight_component, - postfx_shape_weight_entity.has_component(postfx_shape_weight_name)) + postfx_shape_weight_entity.has_component(AtomComponentProperties.postfx_shape())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -139,16 +139,16 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) # 6. Add PostFX Layer component since it is required by the PostFx Shape Weight Modifier component. - postfx_layer_name = "PostFX Layer" - postfx_shape_weight_entity.add_component(postfx_layer_name) - Report.result(Tests.postfx_layer_component, postfx_shape_weight_entity.has_component(postfx_layer_name)) + postfx_shape_weight_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result( + Tests.postfx_layer_component, + postfx_shape_weight_entity.has_component(AtomComponentProperties.postfx_layer())) # 7. Verify PostFx Shape Weight Modifier component is NOT enabled since it also requires a shape. Report.result(Tests.postfx_shape_weight_disabled, not postfx_shape_weight_component.is_enabled()) # 8. Add a required shape looping over a list and checking if it enables PostFX Shape Weight Modifier. - for shape in ['Axis Aligned Box Shape', 'Box Shape', 'Capsule Shape', 'Compound Shape', 'Cylinder Shape', - 'Disk Shape', 'Polygon Prism Shape', 'Quad Shape', 'Sphere Shape', 'Vegetation Reference Shape']: + for shape in AtomComponentProperties.postfx_shape('shapes'): postfx_shape_weight_entity.add_component(shape) test_shape = ( f"Entity has a {shape} component", diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py index 9b13eb2c7e..70adf9143a 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py @@ -87,30 +87,28 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): """ import azlmbr.legacy.general as general - import azlmbr.math as math import azlmbr.render as render from editor_python_test_tools.editor_entity_utils import EditorEntity - from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties with Tracer() as error_tracer: # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. - helper.init_idle() - helper.open_level("", "Base") + TestHelper.init_idle() + TestHelper.open_level("", "Base") # Test steps begin. # 1. Create a Reflection Probe entity with no components. - reflection_probe_name = "Reflection Probe" - reflection_probe_entity = EditorEntity.create_editor_entity_at( - math.Vector3(512.0, 512.0, 34.0), reflection_probe_name) + reflection_probe_entity = EditorEntity.create_editor_entity(AtomComponentProperties.reflection_probe()) Report.critical_result(Tests.reflection_probe_creation, reflection_probe_entity.exists()) # 2. Add a Reflection Probe component to Reflection Probe entity. - reflection_probe_component = reflection_probe_entity.add_component(reflection_probe_name) + reflection_probe_component = reflection_probe_entity.add_component(AtomComponentProperties.reflection_probe()) Report.critical_result( Tests.reflection_probe_component, - reflection_probe_entity.has_component(reflection_probe_name)) + reflection_probe_entity.has_component(AtomComponentProperties.reflection_probe())) # 3. UNDO the entity creation and component addition. # -> UNDO component addition. @@ -139,18 +137,27 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): # 5. Verify Reflection Probe component not enabled. Report.result(Tests.reflection_probe_disabled, not reflection_probe_component.is_enabled()) - # 6. Add Box Shape component since it is required by the Reflection Probe component. - box_shape = "Box Shape" - reflection_probe_entity.add_component(box_shape) - Report.result(Tests.box_shape_component, reflection_probe_entity.has_component(box_shape)) + # 6. Add Shape component since it is required by the Reflection Probe component. + for shape in AtomComponentProperties.reflection_probe('shapes'): + reflection_probe_entity.add_component(shape) + test_shape = ( + f"Entity has a {shape} component", + f"Entity did not have a {shape} component") + Report.result(test_shape, reflection_probe_entity.has_component(shape)) - # 7. Verify Reflection Probe component is enabled. - Report.result(Tests.reflection_probe_enabled, reflection_probe_component.is_enabled()) + # 7. Check if required shape allows Reflection Probe to be enabled + Report.result(Tests.reflection_probe_enabled, reflection_probe_component.is_enabled()) + + # Undo to remove each added shape except the last one and verify Reflection Probe is not enabled. + if not (shape == AtomComponentProperties.reflection_probe('shapes')[-1]): + general.undo() + TestHelper.wait_for_condition(lambda: not reflection_probe_entity.has_component(shape), 1.0) + Report.result(Tests.reflection_probe_disabled, not reflection_probe_component.is_enabled()) # 8. Enter/Exit game mode. - helper.enter_game_mode(Tests.enter_game_mode) + TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) - helper.exit_game_mode(Tests.exit_game_mode) + TestHelper.exit_game_mode(Tests.exit_game_mode) # 9. Test IsHidden. reflection_probe_entity.set_visibility_state(False) @@ -165,8 +172,9 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", reflection_probe_entity.id) Report.result( Tests.reflection_map_generated, - helper.wait_for_condition( - lambda: reflection_probe_component.get_component_property_value("Cubemap|Baked Cubemap Path") != "", + TestHelper.wait_for_condition( + lambda: reflection_probe_component.get_component_property_value( + AtomComponentProperties.reflection_probe('Baked Cubemap Path')) != "", 20.0)) # 12. Delete Reflection Probe entity. @@ -182,7 +190,7 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): Report.result(Tests.deletion_redo, not reflection_probe_entity.exists()) # 15. Look for errors or asserts. - helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") for assert_info in error_tracer.asserts: From 68d9c0537735f86050e327be483cc1e66469ef3c Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 26 Oct 2021 08:14:34 -0700 Subject: [PATCH 073/200] wireframe rendering Signed-off-by: rhhong Signed-off-by: Gene Walters --- .../Code/Source/AtomActorDebugDraw.cpp | 76 +++++++++++++++++++ .../Code/Source/AtomActorDebugDraw.h | 1 + 2 files changed, 77 insertions(+) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp index eaaf04fcf2..836e2c8822 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp @@ -88,6 +88,10 @@ namespace AZ::Render { RenderTangents(mesh, globalTM); } + if (renderWireframe) + { + RenderWireframe(mesh, globalTM); + } } } } @@ -412,4 +416,76 @@ namespace AZ::Render lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); } + + // Render wireframe mesh + void AtomActorDebugDraw::RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) + { + // Check if the mesh is valid and skip the node in case it's not + if (!mesh) + { + return; + } + + RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); + if (!auxGeom) + { + return; + } + + PrepareForMesh(mesh, worldTM); + + const float scale = 0.01f; + + AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); + const AZ::Color vertexColor = AZ::Color(0.8f, 0.24f, 0.88f, 1.0f); + + const size_t numSubMeshes = mesh->GetNumSubMeshes(); + for (uint32 subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex) + { + EMotionFX::SubMesh* subMesh = mesh->GetSubMesh(subMeshIndex); + const uint32 numTriangles = subMesh->GetNumPolygons(); + const uint32 startVertex = subMesh->GetStartVertex(); + const uint32* indices = subMesh->GetIndices(); + + m_auxVertices.clear(); + m_auxVertices.reserve(numTriangles * 6); + m_auxColors.clear(); + m_auxColors.reserve(m_auxVertices.size()); + + for (uint32 triangleIndex = 0; triangleIndex < numTriangles; ++triangleIndex) + { + const uint32 triangleStartIndex = triangleIndex * 3; + const uint32 indexA = indices[triangleStartIndex + 0] + startVertex; + const uint32 indexB = indices[triangleStartIndex + 1] + startVertex; + const uint32 indexC = indices[triangleStartIndex + 2] + startVertex; + + const AZ::Vector3 posA = m_worldSpacePositions[indexA] + normals[indexA] * scale; + const AZ::Vector3 posB = m_worldSpacePositions[indexB] + normals[indexB] * scale; + const AZ::Vector3 posC = m_worldSpacePositions[indexC] + normals[indexC] * scale; + + m_auxVertices.emplace_back(posA); + m_auxColors.emplace_back(vertexColor); + m_auxVertices.emplace_back(posB); + m_auxColors.emplace_back(vertexColor); + + m_auxVertices.emplace_back(posB); + m_auxColors.emplace_back(vertexColor); + m_auxVertices.emplace_back(posC); + m_auxColors.emplace_back(vertexColor); + + m_auxVertices.emplace_back(posC); + m_auxColors.emplace_back(vertexColor); + m_auxVertices.emplace_back(posA); + m_auxColors.emplace_back(vertexColor); + } + } + + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = m_auxColors.data(); + lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } } // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h index 9f8b137f13..797de16351 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h @@ -43,6 +43,7 @@ namespace AZ::Render void RenderEMFXDebugDraw(EMotionFX::ActorInstance* instance); void RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals); void RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); + void RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); EMotionFX::Mesh* m_currentMesh = nullptr; /**< A pointer to the mesh whose world space positions are in the pre-calculated positions buffer. NULL in case we haven't pre-calculated any positions yet. */ From 0f1f429cc1741900df6cf76463435dbed92ebcdc Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 26 Oct 2021 12:28:47 -0700 Subject: [PATCH 074/200] CR feedback. Use one color instead of a color array. Signed-off-by: rhhong Signed-off-by: Gene Walters --- .../Code/Source/AtomActorDebugDraw.cpp | 43 ++++++------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp index 836e2c8822..1325455cd9 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp @@ -259,8 +259,6 @@ namespace AZ::Render m_auxVertices.clear(); m_auxVertices.reserve(numTriangles * 2); - m_auxColors.clear(); - m_auxColors.reserve(m_auxVertices.size()); for (uint32 triangleIndex = 0; triangleIndex < numTriangles; ++triangleIndex) { @@ -279,17 +277,15 @@ namespace AZ::Render const AZ::Vector3 normalPos = (posA + posB + posC) * (1.0f / 3.0f); m_auxVertices.emplace_back(normalPos); - m_auxColors.emplace_back(colorFaceNormals); m_auxVertices.emplace_back(normalPos + (normalDir * faceNormalsScale)); - m_auxColors.emplace_back(colorFaceNormals); } } RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = m_auxColors.data(); - lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_colors = &colorFaceNormals; + lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); } @@ -306,8 +302,6 @@ namespace AZ::Render m_auxVertices.clear(); m_auxVertices.reserve(numVertices * 2); - m_auxColors.clear(); - m_auxColors.reserve(m_auxVertices.size()); for (uint32 j = 0; j < numVertices; ++j) { @@ -316,17 +310,15 @@ namespace AZ::Render const AZ::Vector3 normal = worldTM.TransformVector(normals[vertexIndex]).GetNormalizedSafe() * vertexNormalsScale; m_auxVertices.emplace_back(position); - m_auxColors.emplace_back(colorFaceNormals); m_auxVertices.emplace_back(position + normal); - m_auxColors.emplace_back(colorFaceNormals); } } RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = m_auxColors.data(); - lineArgs.m_colorCount = static_cast(m_auxColors.size()); + lineArgs.m_colors = &colorVertexNormals; + lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); } @@ -417,7 +409,6 @@ namespace AZ::Render auxGeom->DrawLines(lineArgs); } - // Render wireframe mesh void AtomActorDebugDraw::RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) { // Check if the mesh is valid and skip the node in case it's not @@ -436,7 +427,7 @@ namespace AZ::Render const float scale = 0.01f; - AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); + const AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); const AZ::Color vertexColor = AZ::Color(0.8f, 0.24f, 0.88f, 1.0f); const size_t numSubMeshes = mesh->GetNumSubMeshes(); @@ -449,8 +440,6 @@ namespace AZ::Render m_auxVertices.clear(); m_auxVertices.reserve(numTriangles * 6); - m_auxColors.clear(); - m_auxColors.reserve(m_auxVertices.size()); for (uint32 triangleIndex = 0; triangleIndex < numTriangles; ++triangleIndex) { @@ -464,28 +453,22 @@ namespace AZ::Render const AZ::Vector3 posC = m_worldSpacePositions[indexC] + normals[indexC] * scale; m_auxVertices.emplace_back(posA); - m_auxColors.emplace_back(vertexColor); m_auxVertices.emplace_back(posB); - m_auxColors.emplace_back(vertexColor); m_auxVertices.emplace_back(posB); - m_auxColors.emplace_back(vertexColor); m_auxVertices.emplace_back(posC); - m_auxColors.emplace_back(vertexColor); m_auxVertices.emplace_back(posC); - m_auxColors.emplace_back(vertexColor); m_auxVertices.emplace_back(posA); - m_auxColors.emplace_back(vertexColor); } - } - RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; - lineArgs.m_verts = m_auxVertices.data(); - lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = m_auxColors.data(); - lineArgs.m_colorCount = static_cast(m_auxColors.size()); - lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; - auxGeom->DrawLines(lineArgs); + RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; + lineArgs.m_verts = m_auxVertices.data(); + lineArgs.m_vertCount = static_cast(m_auxVertices.size()); + lineArgs.m_colors = &vertexColor; + lineArgs.m_colorCount = 1; + lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; + auxGeom->DrawLines(lineArgs); + } } } // namespace AZ::Render From 171570c3dcb7f2046555c170db26a48421da2c9c Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Tue, 26 Oct 2021 14:37:47 -0700 Subject: [PATCH 075/200] Fix notification queue and add gem action (#4985) Signed-off-by: AMZN-alexpete <26804013+AMZN-alexpete@users.noreply.github.com> Signed-off-by: Gene Walters --- .../Components/ToastNotification.cpp | 9 +- .../Components/ToastNotification.h | 4 +- .../Notifications/ToastNotificationsView.cpp | 34 ++++++++ .../UI/Notifications/ToastNotificationsView.h | 5 ++ .../Source/GemCatalog/GemCatalogScreen.cpp | 87 ++++++++++--------- .../Source/GemCatalog/GemCatalogScreen.h | 1 + 6 files changed, 95 insertions(+), 45 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp index f79f355ccb..8831bef89c 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.cpp @@ -22,6 +22,7 @@ namespace AzQtComponents , m_closeOnClick(true) , m_ui(new Ui::ToastNotification()) , m_fadeAnimation(nullptr) + , m_configuration(toastConfiguration) { setProperty("HasNoWindowDecorations", true); @@ -80,7 +81,13 @@ namespace AzQtComponents } ToastNotification::~ToastNotification() - { + { + } + + bool ToastNotification::IsDuplicate(const ToastConfiguration& toastConfiguration) + { + return toastConfiguration.m_title == m_configuration.m_title + && toastConfiguration.m_description == m_configuration.m_description; } void ToastNotification::paintEvent(QPaintEvent* event) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h index 7f2701a803..4343f37df4 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToastNotification.h @@ -45,6 +45,8 @@ namespace AzQtComponents void ShowToastAtPoint(const QPoint& screenPosition, const QPointF& anchorPoint); void UpdatePosition(const QPoint& screenPosition, const QPointF& anchorPoint); + + bool IsDuplicate(const ToastConfiguration& toastConfiguration); // QDialog void showEvent(QShowEvent* showEvent) override; @@ -64,7 +66,7 @@ namespace AzQtComponents private: QPropertyAnimation* m_fadeAnimation; - + ToastConfiguration m_configuration; bool m_closeOnClick; QTimer m_lifeSpan; uint32_t m_borderRadius = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp index e039230783..a88711a9ed 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.cpp @@ -63,6 +63,12 @@ namespace AzToolsFramework ToastId ToastNotificationsView::ShowToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration) { + // reject duplicate messages + if (m_rejectDuplicates && DuplicateNotificationInQueue(toastConfiguration)) + { + return ToastId(); + } + ToastId toastId = CreateToastNotification(toastConfiguration); m_queuedNotifications.emplace_back(toastId); @@ -70,10 +76,28 @@ namespace AzToolsFramework { DisplayQueuedNotification(); } + else if (m_queuedNotifications.size() >= m_maxQueuedNotifications) + { + // hiding the active toast will cause the next toast to be displayed + HideToastNotification(m_activeNotification); + } return toastId; } + bool ToastNotificationsView::DuplicateNotificationInQueue(const AzQtComponents::ToastConfiguration& toastConfiguration) + { + for (auto iter : m_notifications) + { + if (iter.second && iter.second->IsDuplicate(toastConfiguration)) + { + return true; + } + } + + return false; + } + ToastId ToastNotificationsView::ShowToastAtCursor(const AzQtComponents::ToastConfiguration& toastConfiguration) { ToastId toastId = CreateToastNotification(toastConfiguration); @@ -187,4 +211,14 @@ namespace AzToolsFramework { m_anchorPoint = anchorPoint; } + + void ToastNotificationsView::SetMaxQueuedNotifications(AZ::u32 maxQueuedNotifications) + { + m_maxQueuedNotifications = maxQueuedNotifications; + } + + void ToastNotificationsView::SetRejectDuplicates(bool rejectDuplicates) + { + m_rejectDuplicates = rejectDuplicates; + } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h index e13f129467..c64ce00f4c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Notifications/ToastNotificationsView.h @@ -52,10 +52,13 @@ namespace AzToolsFramework void SetOffset(const QPoint& offset); void SetAnchorPoint(const QPointF& anchorPoint); + void SetMaxQueuedNotifications(AZ::u32 maxQueuedNotifications); + void SetRejectDuplicates(bool rejectDuplicates); private: ToastId CreateToastNotification(const AzQtComponents::ToastConfiguration& toastConfiguration); void DisplayQueuedNotification(); + bool DuplicateNotificationInQueue(const AzQtComponents::ToastConfiguration& toastConfiguration); QPoint GetGlobalPoint(); ToastId m_activeNotification; @@ -64,5 +67,7 @@ namespace AzToolsFramework QPoint m_offset = QPoint(10, 10); QPointF m_anchorPoint = QPointF(1, 0); + AZ::u32 m_maxQueuedNotifications = 5; + bool m_rejectDuplicates = true; }; } // AzToolsFramework diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index b145363460..8b78fa655d 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -42,7 +42,9 @@ namespace O3DE::ProjectManager m_headerWidget = new GemCatalogHeaderWidget(m_gemModel, m_proxModel, m_downloadController); vLayout->addWidget(m_headerWidget); + connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); connect(m_headerWidget, &GemCatalogHeaderWidget::OpenGemsRepo, this, &GemCatalogScreen::HandleOpenGemRepo); + connect(m_headerWidget, &GemCatalogHeaderWidget::AddGem, this, &GemCatalogScreen::OnAddGemClicked); QHBoxLayout* hLayout = new QHBoxLayout(); hLayout->setMargin(0); @@ -73,6 +75,7 @@ namespace O3DE::ProjectManager m_notificationsView = AZStd::make_unique(this, AZ_CRC("GemCatalogNotificationsView")); m_notificationsView->SetOffset(QPoint(10, 70)); + m_notificationsView->SetMaxQueuedNotifications(1); } void GemCatalogScreen::ReinitForProject(const QString& projectPath) @@ -94,48 +97,6 @@ namespace O3DE::ProjectManager m_headerWidget->ReinitForProject(); connect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter); - connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged); - connect( - m_headerWidget, &GemCatalogHeaderWidget::AddGem, - [&]() - { - EngineInfo engineInfo; - QString defaultPath; - - AZ::Outcome engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo(); - if (engineInfoResult.IsSuccess()) - { - engineInfo = engineInfoResult.GetValue(); - defaultPath = engineInfo.m_defaultGemsFolder; - } - - if (defaultPath.isEmpty()) - { - defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); - } - - QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath)); - if (!directory.isEmpty()) - { - // register the gem to the o3de_manifest.json and to the project after the user confirms - // project creation/update - auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory); - if(!registerResult) - { - QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str()); - } - else - { - m_gemsToRegisterWithProject.insert(directory); - AZ::Outcome gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory); - if (gemInfoResult) - { - m_gemModel->AddGem(gemInfoResult.GetValue()); - m_gemModel->UpdateGemDependencies(); - } - } - } - }); // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ @@ -144,6 +105,46 @@ namespace O3DE::ProjectManager }); } + void GemCatalogScreen::OnAddGemClicked() + { + EngineInfo engineInfo; + QString defaultPath; + + AZ::Outcome engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo(); + if (engineInfoResult.IsSuccess()) + { + engineInfo = engineInfoResult.GetValue(); + defaultPath = engineInfo.m_defaultGemsFolder; + } + + if (defaultPath.isEmpty()) + { + defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + } + + QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath)); + if (!directory.isEmpty()) + { + // register the gem to the o3de_manifest.json and to the project after the user confirms + // project creation/update + auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory); + if(!registerResult) + { + QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str()); + } + else + { + m_gemsToRegisterWithProject.insert(directory); + AZ::Outcome gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory); + if (gemInfoResult) + { + m_gemModel->AddGem(gemInfoResult.GetValue()); + m_gemModel->UpdateGemDependencies(); + } + } + } + } + void GemCatalogScreen::OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies) { if (m_notificationsEnabled) @@ -174,7 +175,7 @@ namespace O3DE::ProjectManager } else if (numChangedDependencies > 1) { - notification += QString("%d Gem ").arg(numChangedDependencies) + tr("dependencies"); + notification += QString("%1 Gem ").arg(numChangedDependencies) + tr("dependencies"); } notification += " " + (added ? tr("activated") : tr("deactivated")); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 8e9f31c710..1ade87af0c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -47,6 +47,7 @@ namespace O3DE::ProjectManager public slots: void OnGemStatusChanged(const QModelIndex& modelIndex, uint32_t numChangedDependencies); + void OnAddGemClicked(); protected: void hideEvent(QHideEvent* event) override; From 9b41078774115722926e3cc591adb6873355f61c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:02:55 -0700 Subject: [PATCH 076/200] Fixed potential unused variable 'originalVersion' with 'maybe_unused' attribute. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> Signed-off-by: Gene Walters --- .../Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp index e9d8a42641..36f4947e3d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialAsset.cpp @@ -208,7 +208,7 @@ namespace AZ return; } - const uint32_t originalVersion = m_materialTypeVersion; + [[maybe_unused]] const uint32_t originalVersion = m_materialTypeVersion; bool changesWereApplied = false; From b9486036c3959a7d9602a1a8a16292ac732f5d25 Mon Sep 17 00:00:00 2001 From: sweeneys Date: Mon, 25 Oct 2021 18:50:34 -0700 Subject: [PATCH 077/200] Fix AzTestRunner smoke test on Linux Signed-off-by: sweeneys Signed-off-by: Gene Walters --- .../smoke/test_CLITool_AzTestRunner_Works.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py index b269c9e131..529716aaf3 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py @@ -13,12 +13,20 @@ import os import pytest import subprocess +import ly_test_tools + @pytest.mark.SUITE_smoke class TestCLIToolAzTestRunnerWorks(object): - def test_CLITool_AzTestRunner_Works(self, build_directory): + def test_CLITool_AzTestRunner_ListSelfTests(self, build_directory): file_path = os.path.join(build_directory, "AzTestRunner") help_message = "OKAY Symbol found: AzRunUnitTests" + + if ly_test_tools.WINDOWS: + target_lib = "AzTestRunner.Tests" + else: + target_lib = "libAzTestRunner.Tests" + # Launch AzTestRunner output = subprocess.run( [file_path, "AzTestRunner.Tests", "AzRunUnitTests", "--gtest_list_tests"], capture_output=True, timeout=10 From 0b9c792fda030e4ceb22d02b0ff427e280b27a2a Mon Sep 17 00:00:00 2001 From: sweeneys Date: Mon, 25 Oct 2021 18:54:01 -0700 Subject: [PATCH 078/200] Fix AzTestRunner with correct lib Signed-off-by: sweeneys Signed-off-by: Gene Walters --- .../PythonTests/smoke/test_CLITool_AzTestRunner_Works.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py b/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py index 529716aaf3..df755d5d11 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py +++ b/AutomatedTesting/Gem/PythonTests/smoke/test_CLITool_AzTestRunner_Works.py @@ -27,12 +27,12 @@ class TestCLIToolAzTestRunnerWorks(object): else: target_lib = "libAzTestRunner.Tests" - # Launch AzTestRunner + # Launch AzTestRunner, load self-tests, print test names output = subprocess.run( - [file_path, "AzTestRunner.Tests", "AzRunUnitTests", "--gtest_list_tests"], capture_output=True, timeout=10 + [file_path, target_lib, "AzRunUnitTests", "--gtest_list_tests"], capture_output=True, timeout=10 ) assert ( len(output.stderr) == 0 and output.returncode == 0 ), f"Error occurred while launching {file_path}: {output.stderr}" # Verify help message - assert help_message in str(output.stdout), f"Help Message: {help_message} is not present" + assert help_message in str(output.stdout), f"Help Message: '{help_message}' unexpectedly not present" From 62e6b72e685336cd8dc729ea3eb7b0bb8e723308 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Wed, 27 Oct 2021 00:53:24 -0700 Subject: [PATCH 079/200] Use `aznew` where appropriate for EMotionFX Command subclasses (#4912) Signed-off-by: Chris Burel Signed-off-by: Gene Walters --- .../CommandSystem/Source/AnimGraphNodeGroupCommands.h | 2 +- .../Code/EMotionFX/CommandSystem/Source/CommandManager.cpp | 4 ++-- .../Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h index 014d3b0398..3623bd5cd5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h @@ -60,7 +60,7 @@ namespace CommandSystem const char* GetDescription() const override; MCore::Command* Create() override { - return new CommandAnimGraphAdjustNodeGroup(this); + return aznew CommandAnimGraphAdjustNodeGroup(this); } static AZStd::vector GenerateNodeNameVector(EMotionFX::AnimGraph* animGraph, const AZStd::vector& nodeIDs); diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/CommandManager.cpp b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/CommandManager.cpp index be4626f592..2c646b3504 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/CommandManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/CommandManager.cpp @@ -104,7 +104,7 @@ namespace CommandSystem RegisterCommand(new CommandMotionSetAdjustMotion()); // register node group commands - RegisterCommand(new CommandAdjustNodeGroup()); + RegisterCommand(aznew CommandAdjustNodeGroup()); RegisterCommand(new CommandAddNodeGroup()); RegisterCommand(new CommandRemoveNodeGroup()); @@ -134,7 +134,7 @@ namespace CommandSystem RegisterCommand(aznew CommandAdjustTransitionCondition()); RegisterCommand(new CommandAnimGraphAddNodeGroup()); RegisterCommand(new CommandAnimGraphRemoveNodeGroup()); - RegisterCommand(new CommandAnimGraphAdjustNodeGroup()); + RegisterCommand(aznew CommandAnimGraphAdjustNodeGroup()); RegisterCommand(new CommandAnimGraphAddGroupParameter()); RegisterCommand(new CommandAnimGraphRemoveGroupParameter()); RegisterCommand(new CommandAnimGraphAdjustGroupParameter()); diff --git a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h index 6c57877bd5..640a670e44 100644 --- a/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h +++ b/Gems/EMotionFX/Code/EMotionFX/CommandSystem/Source/NodeGroupCommands.h @@ -63,7 +63,7 @@ namespace CommandSystem const char* GetDescription() const override; MCore::Command* Create() override { - return new CommandAdjustNodeGroup(this); + return aznew CommandAdjustNodeGroup(this); } private: From 47266db100217096e48b39f94201d5af6cb36378 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 27 Oct 2021 02:28:22 -0700 Subject: [PATCH 080/200] bugfix: improve viewport overlay (#4939) * bugfix: improve viewport overlay - disable animation for window - fix problem where vieport is offset from main window Signed-off-by: Michael Pollind * update geometry of m_uiOverlay Signed-off-by: Michael Pollind Signed-off-by: Gene Walters --- .../AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp index 43e2a6793f..5155de3087 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportUi/ViewportUiDisplay.cpp @@ -427,8 +427,8 @@ namespace AzToolsFramework::ViewportUi::Internal void ViewportUiDisplay::PositionUiOverlayOverRenderViewport() { QPoint offset = m_renderOverlay->mapToGlobal(QPoint()); - m_uiMainWindow.move(offset); - m_uiOverlay.setFixedSize(m_renderOverlay->width(), m_renderOverlay->height()); + m_uiMainWindow.setGeometry(offset.x(), offset.y(), m_renderOverlay->width(), m_renderOverlay->height()); + m_uiOverlay.setGeometry(m_uiMainWindow.rect()); UpdateUiOverlayGeometry(); } From 63308c942ad9d053f432c41ae6b170307d83b30a Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed, 27 Oct 2021 08:15:35 -0500 Subject: [PATCH 081/200] {lyn7677} updated test modules to pass AssetPipelineTests on Linux (#5017) * {lyn7677} updated test modules to pass AssetPipelineTests on Linux Fixes for Python AssetPipelineTests modules fail on Linux Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> * Separating the Linux and Mac concerns Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> Signed-off-by: Gene Walters --- .../ap_fixtures/ap_fast_scan_setting_backup_fixture.py | 3 +++ .../asset_processor_batch_dependency_tests.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_fast_scan_setting_backup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_fast_scan_setting_backup_fixture.py index 4a096ca3fe..c224289cf4 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_fast_scan_setting_backup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/ap_fast_scan_setting_backup_fixture.py @@ -29,6 +29,9 @@ def ap_fast_scan_setting_backup_fixture(request, workspace) -> PlatformSetting: if workspace.asset_processor_platform == 'mac': pytest.skip("Mac plist file editing not implemented yet") + if workspace.asset_processor_platform == 'linux': + pytest.skip("Linux system settings not implemented yet") + key = fast_scan_key subkey = fast_scan_subkey 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 ee8e177bbb..264f690534 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 @@ -79,7 +79,7 @@ class TestsAssetProcessorBatch_DependenycyTests(object): 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_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")) From 21b349fcfa6c32bf349436d8935c3e8cef4b7bf8 Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Wed, 27 Oct 2021 09:30:24 -0400 Subject: [PATCH 082/200] Hair - bug fix of changing the method by which passes are acquired (#5015) Signed-off-by: Adi-Amazon Signed-off-by: Adi-Amazon <82479970+Adi-Amazon@users.noreply.github.com> Co-authored-by: Adi-Amazon Signed-off-by: Gene Walters --- .../Code/Rendering/HairFeatureProcessor.cpp | 13 +++++++------ .../Code/Rendering/HairFeatureProcessor.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp index 161160e16f..74ba99c26c 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.cpp @@ -311,17 +311,17 @@ namespace AZ m_forceClearRenderData = true; } - bool HairFeatureProcessor::HasHairParentPass() + bool HairFeatureProcessor::HasHairParentPass(RPI::RenderPipeline* renderPipeline) { - RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene()); + RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, renderPipeline); RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter); - return pass; + return pass ? true : false; } void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!HasHairParentPass()) + if (!HasHairParentPass(renderPipeline.get())) { return; } @@ -335,7 +335,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!HasHairParentPass()) + if (!HasHairParentPass(renderPipeline)) { return; } @@ -347,7 +347,7 @@ namespace AZ void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) { // Proceed only if this is the main pipeline that contains the parent pass - if (!HasHairParentPass()) + if (!HasHairParentPass(renderPipeline)) { return; } @@ -623,3 +623,4 @@ namespace AZ } // namespace Hair } // namespace Render } // namespace AZ + diff --git a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h index f810967824..70e37a7863 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h @@ -165,7 +165,7 @@ namespace AZ void EnablePasses(bool enable); - bool HasHairParentPass(); + bool HasHairParentPass(RPI::RenderPipeline* renderPipeline); //! The following will serve to register the FP in the Thumbnail system AZStd::vector m_hairFeatureProcessorRegistryName; From e9cf7cb62406e2f11a7fd5aabb9129c2f2d05ac5 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Wed, 27 Oct 2021 10:12:13 -0500 Subject: [PATCH 083/200] Detail material Id texture created from surface weights. (#4984) * Added some structs for detail materials Signed-off-by: Ken Pruiksma * Added some template functions for looking up materials. Added lookups for all the relevant detail material fields in StandardPBR. Signed-off-by: Ken Pruiksma * Added some structs for detail materials Signed-off-by: Ken Pruiksma * Added some template functions for looking up materials. Added lookups for all the relevant detail material fields in StandardPBR. Signed-off-by: Ken Pruiksma * Added support for generating a detail material texture with IDs populated from surface weights. Signed-off-by: Ken Pruiksma * Updated TerrainAreaMaterailRequestBus to have separate calls for region vs materials instead of the awkward out parameter Update MaterialPropertyDescriptor so that you can retrieve enum names by ID Several bug fixes / updates to the terrain feature processor dealing with detail materials. Signed-off-by: Ken Pruiksma * Updating detail material texture based on offsets. Not quite working yet but close. Added visualization for detail material in shader (currently on, will be turned off before final commit) Signed-off-by: Ken Pruiksma * Small bugfixes * Fix compile error in non-unity builds * Fixed backwards x/y loops causing the wrong pixels to update * Fixed selection of surface type with multiple surface weights Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Adding seam to detail texture debug display. Offseting edges by a half-pixel to avoid bleed. Disabling debugging detail textures by default. Signed-off-by: Ken Pruiksma * Missing file from last commit for detail material change. Signed-off-by: Ken Pruiksma * Cleanups Signed-off-by: Ken Pruiksma * bug fix Signed-off-by: Ken Pruiksma * Bug fix in the terrain fp for TerrainAreaMaterialRequestBus returning incomplete materials on GetSurfaceMaterialMappings Signed-off-by: Ken Pruiksma * Some PR updates. Exposing detail material id debugging through a cvar. Signed-off-by: Ken Pruiksma * Various updates from review. Signed-off-by: Ken Pruiksma * PR updates dealing with debug texture boundary line. Signed-off-by: Ken Pruiksma * Hiding some fields from the terrain material Signed-off-by: Ken Pruiksma * Fixing type in generic lambda for linux / android Signed-off-by: Ken Pruiksma Co-authored-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Signed-off-by: Gene Walters --- .../Material/MaterialPropertyDescriptor.h | 3 + .../Material/MaterialPropertyDescriptor.cpp | 10 + .../Materials/Terrain/PbrTerrain.materialtype | 47 +- .../Shaders/Terrain/TerrainCommon.azsli | 14 + .../Terrain/TerrainPBR_ForwardPass.azsl | 45 ++ .../TerrainSurfaceMaterialsListComponent.cpp | 19 +- .../TerrainSurfaceMaterialsListComponent.h | 5 +- .../TerrainAreaMaterialRequestBus.h | 9 +- .../TerrainFeatureProcessor.cpp | 734 +++++++++++++++++- .../TerrainRenderer/TerrainFeatureProcessor.h | 155 +++- 10 files changed, 992 insertions(+), 49 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h index 085256f6d8..76bb2a6113 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h @@ -106,6 +106,9 @@ namespace AZ static constexpr uint32_t InvalidEnumValue = std::numeric_limits::max(); uint32_t GetEnumValue(const AZ::Name& enumName) const; + //! Returns the name of the enum from its index. An empty name is returned for an invalid id. + const AZ::Name& GetEnumName(uint32_t enumValue) const; + //! Returns the unique name ID of this property const Name& GetName() const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp index 700ac41003..5d0a88a6d3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/MaterialPropertyDescriptor.cpp @@ -203,6 +203,16 @@ namespace AZ return InvalidEnumValue; } + + const AZ::Name& MaterialPropertyDescriptor::GetEnumName(uint32_t enumValue) const + { + if (enumValue < m_enumNames.size()) + { + return m_enumNames.at(enumValue); + } + static AZ::Name EmptyName = AZ::Name(); + return EmptyName; + } } // namespace RPI } // namespace AZ diff --git a/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype b/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype index 01b862c4f8..235079d95e 100644 --- a/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype +++ b/Gems/Terrain/Assets/Materials/Terrain/PbrTerrain.materialtype @@ -92,13 +92,58 @@ { "id": "heightmapImage", "displayName": "Heightmap Image", - "description": "Heightmap of the terrain, controlled by the runtime.", + "description": "Heightmap of the terrain. Controlled by the runtime.", + "visibility": "Hidden", "type": "Image", "connection": { "type": "ShaderInput", "id": "m_heightmapImage" } }, + { + "id": "detailMaterialIdImage", + "displayName": "Detail Material Id Image", + "description": "Texture containing detail material Ids and weights. Controlled by the runtime.", + "visibility": "Hidden", + "type": "Image", + "connection": { + "type": "ShaderInput", + "id": "m_detailMaterialIdImage" + } + }, + { + "id": "detailMaterialIdCenter", + "displayName": "Detail Material Id Image Center", + "description": "The center position of the detail material Id image. Controlled by the runtime.", + "visibility": "Hidden", + "type": "Vector2", + "connection": { + "type": "ShaderInput", + "id": "m_detailMaterialIdImageCenter" + } + }, + { + "id": "detailAabb", + "displayName": "Detail material bounds in 2d", + "description": "The 2d world space bounds of the detail id material. Controlled by the runtime.", + "visibility": "Hidden", + "type": "Vector4", + "connection": { + "type": "ShaderInput", + "id": "m_detailAabb" + } + }, + { + "id": "detailHalfPixelUv", + "displayName": "Detail texture half pixel uv size", + "description": "Uv size of a half pixel in the detail material id texture. Controlled by the runtime.", + "visibility": "Hidden", + "type": "float", + "connection": { + "type": "ShaderInput", + "id": "m_detailHalfPixelUv" + } + }, { "id": "detailTextureMultiplier", "displayName": "Detail Texture UV Multiplier", diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli index 72c1af953c..dc6f65207b 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainCommon.azsli @@ -93,10 +93,15 @@ ShaderResourceGroup ObjectSrg : SRG_PerObject ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial { Texture2D m_heightmapImage; + Texture2D m_detailMaterialIdImage; + float2 m_detailMaterialIdImageCenter; float m_detailTextureMultiplier; float m_detailFadeDistance; float m_detailFadeLength; + float4 m_detailAabb; + float m_detailHalfPixelUv; + Sampler HeightmapSampler { MinFilter = Linear; @@ -117,6 +122,15 @@ ShaderResourceGroup TerrainMaterialSrg : SRG_PerMaterial MaxAnisotropy = 16; }; + Sampler m_detailSampler + { + AddressU = Wrap; + AddressV = Wrap; + MinFilter = Point; + MagFilter = Point; + MipFilter = Point; + }; + // Base Color float3 m_baseColor; float m_baseColorFactor; diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl index 750cd2fb29..a15ad931f6 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl @@ -17,6 +17,7 @@ #include #include #include +#include struct VSOutput { @@ -29,6 +30,8 @@ struct VSOutput float2 m_uv : UV1; }; +option bool o_debugDetailMaterialIds = false; + VSOutput TerrainPBR_MainPassVS(VertexInput IN) { VSOutput OUT; @@ -121,6 +124,48 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) float3 detailColor = GetBaseColorInput(TerrainMaterialSrg::m_baseColorMap, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture); float3 blendedColor = BlendBaseColor(lerp(detailColor, TerrainMaterialSrg::m_baseColor.rgb, detailFactor), macroColor, TerrainMaterialSrg::m_baseColorFactor, o_baseColorTextureBlendMode, o_baseColor_useTexture); + // ------- Debug detail materials using random colors ------- + // This assigns a random color to each material, turns off any kind of distance fading, and draws a black line at the texture edges. + if (o_debugDetailMaterialIds) + { + float2 detailRegionMin = TerrainMaterialSrg::m_detailAabb.xy; + float2 detailRegionMax = TerrainMaterialSrg::m_detailAabb.zw; + float2 detailRegionUv = (surface.position.xy - detailRegionMin) / (detailRegionMax - detailRegionMin); + if (all(detailRegionUv > TerrainMaterialSrg::m_detailHalfPixelUv) && all(detailRegionUv < 1.0 - TerrainMaterialSrg::m_detailHalfPixelUv)) + { + detailRegionUv += TerrainMaterialSrg::m_detailMaterialIdImageCenter - (0.5); + + uint material1 = TerrainMaterialSrg::m_detailMaterialIdImage.GatherRed(TerrainMaterialSrg::m_detailSampler, detailRegionUv, 0).r; + uint material2 = TerrainMaterialSrg::m_detailMaterialIdImage.GatherGreen(TerrainMaterialSrg::m_detailSampler, detailRegionUv, 0).r; + float blend = float(TerrainMaterialSrg::m_detailMaterialIdImage.GatherBlue(TerrainMaterialSrg::m_detailSampler, detailRegionUv, 0).r) / 0xFF; + + float3 material1Color = float3(0.1, 0.1, 0.1); + float3 material2Color = float3(0.1, 0.1, 0.1); + + // Get a reasonably random hue for the material id + if (material1 != 255) + { + float hue1 = (material1 * 25043 % 256) / 256.0; + material1Color = HsvToRgb(float3(hue1, 1.0, 1.0)); + } + if (material2 != 255) + { + float hue2 = (material2 * 25043 % 256) / 256.0; + material2Color = HsvToRgb(float3(hue2, 1.0, 1.0)); + } + + blendedColor = lerp(material1Color, material2Color, blend); + float seamBlend = 0.0; + const float halfLineWidth = 1.0 / 2048.0; + if (any(abs(detailRegionUv) % 1.0 < halfLineWidth) || any(abs(detailRegionUv) % 1.0 > 1.0 - halfLineWidth)) + { + seamBlend = 1.0; + } + blendedColor = lerp(blendedColor, float3(0.0, 0.0, 0.0), seamBlend); // draw texture seams + blendedColor = pow(blendedColor , 2.2); + } + } + // ------- Specular ------- float specularF0Factor = GetSpecularInput(TerrainMaterialSrg::m_specularF0Map, TerrainMaterialSrg::m_sampler, detailUv, TerrainMaterialSrg::m_specularF0Factor, o_specularF0_useTexture); specularF0Factor = lerp(specularF0Factor, 0.5, detailFactor); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp index 271919070c..3c6a213b02 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp @@ -123,20 +123,23 @@ namespace Terrain { surfaceMaterialMapping.m_active = false; surfaceMaterialMapping.m_materialAsset.QueueLoad(); - AZ::Data::AssetBus::Handler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId()); + AZ::Data::AssetBus::MultiHandler::BusConnect(surfaceMaterialMapping.m_materialAsset.GetId()); } } + + // Announce initial shape using OnShapeChanged + OnShapeChanged(LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged); } void TerrainSurfaceMaterialsListComponent::Deactivate() { TerrainAreaMaterialRequestBus::Handler::BusDisconnect(); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(); for (auto& surfaceMaterialMapping : m_configuration.m_surfaceMaterials) { if (surfaceMaterialMapping.m_materialAsset.GetId().IsValid()) { - AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_materialAsset.GetId()); surfaceMaterialMapping.m_materialAsset.Release(); surfaceMaterialMapping.m_materialInstance.reset(); surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId(); @@ -202,7 +205,7 @@ namespace Terrain // Don't disconnect from the AssetBus if this material is mapped more than once. if (CountMaterialIDInstances(surfaceMaterialMapping.m_activeMaterialAssetId) == 1) { - AZ::Data::AssetBus::Handler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId); + AZ::Data::AssetBus::MultiHandler::BusDisconnect(surfaceMaterialMapping.m_activeMaterialAssetId); } surfaceMaterialMapping.m_activeMaterialAssetId = AZ::Data::AssetId(); @@ -273,12 +276,14 @@ namespace Terrain &TerrainAreaMaterialNotificationBus::Events::OnTerrainSurfaceMaterialMappingRegionChanged, GetEntityId(), oldAabb, m_cachedAabb); } - - const AZStd::vector& TerrainSurfaceMaterialsListComponent::GetSurfaceMaterialMappings( - AZ::Aabb& region) const + + const AZ::Aabb& TerrainSurfaceMaterialsListComponent::GetTerrainSurfaceMaterialRegion() const { - region = m_cachedAabb; + return m_cachedAabb; + } + const AZStd::vector& TerrainSurfaceMaterialsListComponent::GetSurfaceMaterialMappings() const + { return m_configuration.m_surfaceMaterials; } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h index 7c36033c41..0e32cb12c0 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h @@ -53,7 +53,7 @@ namespace Terrain class TerrainSurfaceMaterialsListComponent : public AZ::Component , private TerrainAreaMaterialRequestBus::Handler - , private AZ::Data::AssetBus::Handler + , private AZ::Data::AssetBus::MultiHandler , private LmbrCentral::ShapeComponentNotificationsBus::Handler { public: @@ -86,7 +86,8 @@ namespace Terrain ////////////////////////////////////////////////////////////////////////// // TerrainAreaMaterialRequestBus - const AZStd::vector& GetSurfaceMaterialMappings(AZ::Aabb& region) const override; + const AZ::Aabb& GetTerrainSurfaceMaterialRegion() const override; + const AZStd::vector& GetSurfaceMaterialMappings() const override; ////////////////////////////////////////////////////////////////////////// // AZ::Data::AssetBus::Handler diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainAreaMaterialRequestBus.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainAreaMaterialRequestBus.h index dfedf0b34a..ae36a2639e 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainAreaMaterialRequestBus.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainAreaMaterialRequestBus.h @@ -9,13 +9,9 @@ #pragma once #include - #include - #include -#include - namespace Terrain { //! This bus provides retrieval of information from Terrain Surfaces. @@ -30,8 +26,11 @@ namespace Terrain virtual ~TerrainAreaMaterialRequests() = default; + //! Get the Aabb for the region where a TerrainSurfaceMaterialMapping exists + virtual const AZ::Aabb& GetTerrainSurfaceMaterialRegion() const = 0; + //! Get the Material asset assigned to a particular surface tag. - virtual const AZStd::vector& GetSurfaceMaterialMappings(AZ::Aabb& region) const = 0; + virtual const AZStd::vector& GetSurfaceMaterialMappings() const = 0; }; using TerrainAreaMaterialRequestBus = AZ::EBus; diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index e6aed28897..571d109fd8 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -7,11 +7,13 @@ */ #include +#include +#include +#include #include #include #include -#include #include @@ -45,12 +47,49 @@ namespace Terrain { [[maybe_unused]] const char* TerrainFPName = "TerrainFeatureProcessor"; const char* TerrainHeightmapChars = "TerrainHeightmap"; + const char* TerrainDetailChars = "TerrainDetail"; } namespace MaterialInputs { // Terrain material static const char* const HeightmapImage("settings.heightmapImage"); + static const char* const DetailMaterialIdImage("settings.detailMaterialIdImage"); + static const char* const DetailCenter("settings.detailMaterialIdCenter"); + static const char* const DetailAabb("settings.detailAabb"); + static const char* const DetailHalfPixelUv("settings.detailHalfPixelUv"); + } + + namespace DetailMaterialInputs + { + static const char* const BaseColorMap("baseColor.textureMap"); + static const char* const BaseColorUseTexture("baseColor.useTexture"); + static const char* const BaseColorFactor("baseColor.factor"); + static const char* const BaseColorBlendMode("baseColor.textureBlendMode"); + static const char* const MetallicMap("metallic.textureMap"); + static const char* const MetallicUseTexture("metallic.useTexture"); + static const char* const MetallicFactor("metallic.factor"); + static const char* const RoughnessMap("roughness.textureMap"); + static const char* const RoughnessUseTexture("roughness.useTexture"); + static const char* const RoughnessFactor("roughness.factor"); + static const char* const RoughnessUpperBound("roughness.lowerBound"); + static const char* const RoughnessLowerBound("roughness.upperBound"); + static const char* const SpecularF0Map("specularF0.textureMap"); + static const char* const SpecularF0UseTexture("specularF0.useTexture"); + static const char* const SpecularF0Factor("specularF0.factor"); + static const char* const NormalMap("normal.textureMap"); + static const char* const NormalUseTexture("normal.useTexture"); + static const char* const NormalFactor("normal.factor"); + static const char* const NormalFlipX("normal.flipX"); + static const char* const NormalFlipY("normal.flipY"); + static const char* const DiffuseOcclusionMap("occlusion.diffuseTextureMap"); + static const char* const DiffuseOcclusionUseTexture("occlusion.diffuseUseTexture"); + static const char* const DiffuseOcclusionFactor("occlusion.diffuseFactor"); + static const char* const HeightMap("parallax.textureMap"); + static const char* const HeightUseTexture("parallax.useTexture"); + static const char* const HeightFactor("parallax.factor"); + static const char* const HeightOffset("parallax.offset"); + static const char* const HeightBlendFactor("parallax.blendFactor"); } namespace ShaderInputs @@ -62,6 +101,17 @@ namespace Terrain static const char* const MacroColorMap("m_macroColorMap"); static const char* const MacroNormalMap("m_macroNormalMap"); } + + AZ_CVAR(bool, + r_terrainDebugDetailMaterials, + false, + [](const bool& value) + { + AZ::RPI::ShaderSystemInterface::Get()->SetGlobalShaderOption(AZ::Name{ "o_debugDetailMaterialIds" }, AZ::RPI::ShaderOptionValue{ value }); + }, + AZ::ConsoleFunctorFlags::Null, + "Turns on debugging for detail material ids for terrain." + ); void TerrainFeatureProcessor::Reflect(AZ::ReflectContext* context) @@ -78,6 +128,12 @@ namespace Terrain { Initialize(); AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); + + m_handleGlobalShaderOptionUpdate = AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler + { + [this](const AZ::Name&, AZ::RPI::ShaderOptionValue) { m_forceRebuildDrawPackets = true; } + }; + AZ::RPI::ShaderSystemInterface::Get()->Connect(m_handleGlobalShaderOptionUpdate); } void TerrainFeatureProcessor::Initialize() @@ -139,11 +195,18 @@ namespace Terrain void TerrainFeatureProcessor::OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) { - if ((dataChangedMask & (TerrainDataChangedMask::HeightData | TerrainDataChangedMask::Settings)) == 0) + if ((dataChangedMask & (TerrainDataChangedMask::HeightData | TerrainDataChangedMask::Settings)) != 0) { - return; + TerrainHeightOrSettingsUpdated(dirtyRegion); + } + if ((dataChangedMask & TerrainDataChangedMask::SurfaceData) != 0) + { + TerrainSurfaceDataUpdated(dirtyRegion); } + } + void TerrainFeatureProcessor::TerrainHeightOrSettingsUpdated(const AZ::Aabb& dirtyRegion) + { AZ::Aabb worldBounds = AZ::Aabb::CreateNull(); AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( worldBounds, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb); @@ -177,10 +240,15 @@ namespace Terrain m_areaData.m_sampleSpacing = queryResolution.GetX(); m_areaData.m_heightmapUpdated = true; } - + + void TerrainFeatureProcessor::TerrainSurfaceDataUpdated(const AZ::Aabb& dirtyRegion) + { + m_dirtyDetailRegion.AddAabb(dirtyRegion); + } + void TerrainFeatureProcessor::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& newMaterialData) { - MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId); + MacroMaterialData& materialData = FindOrCreateByEntityId(entityId, m_macroMaterials); UpdateMacroMaterialData(materialData, newMaterialData); @@ -197,14 +265,14 @@ namespace Terrain void TerrainFeatureProcessor::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& newMaterialData) { - MacroMaterialData& data = FindOrCreateMacroMaterial(entityId); + MacroMaterialData& data = FindOrCreateByEntityId(entityId, m_macroMaterials); UpdateMacroMaterialData(data, newMaterialData); } void TerrainFeatureProcessor::OnTerrainMacroMaterialRegionChanged( AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) { - MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId); + MacroMaterialData& materialData = FindOrCreateByEntityId(entityId, m_macroMaterials); for (SectorData& sectorData : m_sectorData) { bool overlapsOld = sectorData.m_aabb.Overlaps(materialData.m_bounds); @@ -236,7 +304,7 @@ namespace Terrain void TerrainFeatureProcessor::OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) { - MacroMaterialData* materialData = FindMacroMaterial(entityId); + const MacroMaterialData* materialData = FindByEntityId(entityId, m_macroMaterials); if (materialData) { @@ -255,13 +323,461 @@ namespace Terrain } m_areaData.m_macroMaterialsUpdated = true; - RemoveMacroMaterial(entityId); + RemoveByEntityId(entityId, m_macroMaterials); } - void TerrainFeatureProcessor::UpdateTerrainData() + void TerrainFeatureProcessor::OnTerrainSurfaceMaterialMappingCreated(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, MaterialInstance material) + { + DetailMaterialListRegion& materialRegion = FindOrCreateByEntityId(entityId, m_detailMaterialRegions); + + // Validate that the surface tag is new + for (DetailMaterialSurface& surface : materialRegion.m_materialsForSurfaces) + { + if (surface.m_surfaceTag == surfaceTag) + { + AZ_Error(TerrainFPName, false, "Already have a surface material mapping for this surface tag."); + return; + } + } + + uint16_t detailMaterialId = CreateOrUpdateDetailMaterial(material); + materialRegion.m_materialsForSurfaces.push_back({ surfaceTag, detailMaterialId }); + m_dirtyDetailRegion.AddAabb(materialRegion.m_region); + } + + void TerrainFeatureProcessor::OnTerrainSurfaceMaterialMappingDestroyed(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag) + { + DetailMaterialListRegion& materialRegion = FindOrCreateByEntityId(entityId, m_detailMaterialRegions); + + for (DetailMaterialSurface& surface : materialRegion.m_materialsForSurfaces) + { + if (surface.m_surfaceTag == surfaceTag) + { + if (surface.m_surfaceTag != materialRegion.m_materialsForSurfaces.back().m_surfaceTag) + { + AZStd::swap(surface, materialRegion.m_materialsForSurfaces.back()); + } + materialRegion.m_materialsForSurfaces.pop_back(); + m_dirtyDetailRegion.AddAabb(materialRegion.m_region); + return; + } + } + AZ_Error(TerrainFPName, false, "Could not find surface tag to destroy for OnTerrainSurfaceMaterialMappingDestroyed()."); + } + + void TerrainFeatureProcessor::OnTerrainSurfaceMaterialMappingChanged(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, MaterialInstance material) + { + DetailMaterialListRegion& materialRegion = FindOrCreateByEntityId(entityId, m_detailMaterialRegions); + + bool found = false; + uint16_t materialId = CreateOrUpdateDetailMaterial(material); + for (DetailMaterialSurface& surface : materialRegion.m_materialsForSurfaces) + { + if (surface.m_surfaceTag == surfaceTag) + { + found = true; + surface.m_detailMaterialId = materialId; + break; + } + } + + if (!found) + { + materialRegion.m_materialsForSurfaces.push_back({ surfaceTag, materialId }); + } + m_dirtyDetailRegion.AddAabb(materialRegion.m_region); + } + + void TerrainFeatureProcessor::OnTerrainSurfaceMaterialMappingRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) + { + DetailMaterialListRegion& materialRegion = FindOrCreateByEntityId(entityId, m_detailMaterialRegions); + materialRegion.m_region = newRegion; + m_dirtyDetailRegion.AddAabb(oldRegion); + m_dirtyDetailRegion.AddAabb(newRegion); + } + + uint16_t TerrainFeatureProcessor::CreateOrUpdateDetailMaterial(MaterialInstance material) + { + static constexpr uint16_t InvalidDetailMaterial = 0xFFFF; + uint16_t detailMaterialId = InvalidDetailMaterial; + + for (DetailMaterialData& detailMaterial : m_detailMaterials.GetDataVector()) + { + if (detailMaterial.m_assetId == material->GetAssetId()) + { + UpdateDetailMaterialData(detailMaterial, material); + detailMaterialId = m_detailMaterials.GetIndexForData(&detailMaterial); + break; + } + } + + if (detailMaterialId == InvalidDetailMaterial) + { + detailMaterialId = m_detailMaterials.GetFreeSlotIndex(); + UpdateDetailMaterialData(m_detailMaterials.GetData(detailMaterialId), material); + } + return detailMaterialId; + } + + void TerrainFeatureProcessor::UpdateDetailMaterialData(DetailMaterialData& materialData, MaterialInstance material) + { + if (materialData.m_materialChangeId != material->GetCurrentChangeId()) + { + materialData = DetailMaterialData(); + DetailTextureFlags& flags = materialData.m_properties.m_flags; + materialData.m_materialChangeId = material->GetCurrentChangeId(); + materialData.m_assetId = material->GetAssetId(); + + auto getIndex = [&](const char* const indexName) -> AZ::RPI::MaterialPropertyIndex + { + const AZ::RPI::MaterialPropertyIndex index = material->FindPropertyIndex(AZ::Name(indexName)); + AZ_Warning(TerrainFPName, index.IsValid(), "Failed to find shader input constant %s.", indexName); + return index; + }; + + auto applyProperty = [&](const char* const indexName, auto& ref) -> void + { + const auto index = getIndex(indexName); + if (index.IsValid()) + { + using TypeRefRemoved = AZStd::remove_cvref_t; + ref = material->GetPropertyValue(index).GetValue(); + } + }; + + auto applyFlag = [&](const char* const indexName, DetailTextureFlags flagToSet) -> void + { + const auto index = getIndex(indexName); + if (index.IsValid()) + { + bool flagValue = material->GetPropertyValue(index).GetValue(); + flags = DetailTextureFlags(flagValue ? flags | flagToSet : flags); + } + }; + + auto getEnumName = [&](const char* const indexName) -> const AZStd::string_view + { + const auto index = getIndex(indexName); + if (index.IsValid()) + { + uint32_t enumIndex = material->GetPropertyValue(index).GetValue(); + const AZ::Name& enumName = material->GetMaterialPropertiesLayout()->GetPropertyDescriptor(index)->GetEnumName(enumIndex); + return enumName.GetStringView(); + } + return ""; + }; + + using namespace DetailMaterialInputs; + applyProperty(BaseColorMap, materialData.m_colorImage); + applyFlag(BaseColorUseTexture, DetailTextureFlags::UseTextureBaseColor); + applyProperty(BaseColorFactor, materialData.m_properties.m_baseColorFactor); + + const AZStd::string_view& blendModeString = getEnumName(BaseColorBlendMode); + if (blendModeString == "Multiply") + { + flags = DetailTextureFlags(flags | DetailTextureFlags::BlendModeMultiply); + } + else if (blendModeString == "LinearLight") + { + flags = DetailTextureFlags(flags | DetailTextureFlags::BlendModeLinearLight); + } + else if (blendModeString == "Lerp") + { + flags = DetailTextureFlags(flags | DetailTextureFlags::BlendModeLerp); + } + else if (blendModeString == "Overlay") + { + flags = DetailTextureFlags(flags | DetailTextureFlags::BlendModeOverlay); + } + + applyProperty(MetallicMap, materialData.m_metalnessImage); + applyFlag(MetallicUseTexture, DetailTextureFlags::UseTextureMetallic); + applyProperty(MetallicFactor, materialData.m_properties.m_metalFactor); + + applyProperty(RoughnessMap, materialData.m_roughnessImage); + applyFlag(RoughnessUseTexture, DetailTextureFlags::UseTextureRoughness); + + if ((flags & DetailTextureFlags::UseTextureRoughness) > 0) + { + float lowerBound = 0.0; + float upperBound = 1.0; + applyProperty(RoughnessLowerBound, lowerBound); + applyProperty(RoughnessUpperBound, upperBound); + materialData.m_properties.m_roughnessBias = lowerBound; + materialData.m_properties.m_roughnessScale = upperBound - lowerBound; + } + else + { + materialData.m_properties.m_roughnessBias = 0.0; + applyProperty(RoughnessFactor, materialData.m_properties.m_roughnessScale); + } + + applyProperty(SpecularF0Map, materialData.m_specularF0Image); + applyFlag(SpecularF0UseTexture, DetailTextureFlags::UseTextureSpecularF0); + applyProperty(SpecularF0Factor, materialData.m_properties.m_specularF0Factor); + + applyProperty(NormalMap, materialData.m_normalImage); + applyFlag(NormalUseTexture, DetailTextureFlags::UseTextureNormal); + applyProperty(NormalFactor, materialData.m_properties.m_normalFactor); + applyFlag(NormalFlipX, DetailTextureFlags::FlipNormalX); + applyFlag(NormalFlipY, DetailTextureFlags::FlipNormalY); + + applyProperty(DiffuseOcclusionMap, materialData.m_occlusionImage); + applyFlag(DiffuseOcclusionUseTexture, DetailTextureFlags::UseTextureOcclusion); + applyProperty(DiffuseOcclusionFactor, materialData.m_properties.m_occlusionFactor); + + applyProperty(HeightMap, materialData.m_heightImage); + applyFlag(HeightUseTexture, DetailTextureFlags::UseTextureHeight); + applyProperty(HeightFactor, materialData.m_properties.m_heightFactor); + applyProperty(HeightOffset, materialData.m_properties.m_heightOffset); + applyProperty(HeightBlendFactor, materialData.m_properties.m_heightBlendFactor); + + } + } + + void TerrainFeatureProcessor::CheckUpdateDetailTexture(const Aabb2i& newBounds, const Vector2i& newCenter) { - static const AZ::Name TerrainHeightmapName = AZ::Name(TerrainHeightmapChars); + if (!m_detailTextureImage) + { + // If the m_detailTextureImage doesn't exist, create it and populate the entire texture + + const AZ::Data::Instance imagePool = AZ::RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool(); + AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D( + AZ::RHI::ImageBindFlags::ShaderRead, DetailTextureSize, DetailTextureSize, AZ::RHI::Format::R8G8B8A8_UINT + ); + const AZ::Name TerrainDetailName = AZ::Name(TerrainDetailChars); + m_detailTextureImage = AZ::RPI::AttachmentImage::Create(*imagePool.get(), imageDescriptor, TerrainDetailName, nullptr, nullptr); + AZ_Error(TerrainFPName, m_detailTextureImage, "Failed to initialize the detail texture image."); + + UpdateDetailTexture(newBounds, newBounds, newCenter); + } + else + { + // If the new bounds of the detail texture are different than the old bounds, then the edges of the texture need to be updated. + + int32_t offsetX = m_detailTextureBounds.m_min.m_x - newBounds.m_min.m_x; + + // Horizontal edge update + if (newBounds.m_min.m_x != m_detailTextureBounds.m_min.m_x) + { + Aabb2i updateBounds; + if (newBounds.m_min.m_x < m_detailTextureBounds.m_min.m_x) + { + updateBounds.m_min.m_x = newBounds.m_min.m_x; + updateBounds.m_max.m_x = m_detailTextureBounds.m_min.m_x; + } + else + { + updateBounds.m_min.m_x = m_detailTextureBounds.m_max.m_x; + updateBounds.m_max.m_x = newBounds.m_max.m_x; + } + updateBounds.m_min.m_y = newBounds.m_min.m_y; + updateBounds.m_max.m_y = newBounds.m_max.m_y; + UpdateDetailTexture(updateBounds, newBounds, newCenter); + } + + // Vertical edge update + if (newBounds.m_min.m_y != m_detailTextureBounds.m_min.m_y) + { + Aabb2i updateBounds; + // Don't update areas that have already been updated in the horizontal update. + updateBounds.m_min.m_x = newBounds.m_min.m_x + AZ::GetMax(0, offsetX); + updateBounds.m_max.m_x = newBounds.m_max.m_x + AZ::GetMin(0, offsetX); + if (newBounds.m_min.m_y < m_detailTextureBounds.m_min.m_y) + { + updateBounds.m_min.m_y = newBounds.m_min.m_y; + updateBounds.m_max.m_y = m_detailTextureBounds.m_min.m_y; + } + else + { + updateBounds.m_min.m_y = m_detailTextureBounds.m_max.m_y; + updateBounds.m_max.m_y = newBounds.m_max.m_y; + } + UpdateDetailTexture(updateBounds, newBounds, newCenter); + } + if (m_dirtyDetailRegion.IsValid()) + { + // If any regions are marked as dirty, then they should be updated. + + AZ::Vector3 currentMin = AZ::Vector3(newBounds.m_min.m_x * DetailTextureScale, newBounds.m_min.m_y * DetailTextureScale, -0.5f); + AZ::Vector3 currentMax = AZ::Vector3(newBounds.m_max.m_x * DetailTextureScale, newBounds.m_max.m_y * DetailTextureScale, 0.5f); + AZ::Aabb detailTextureCoverage = AZ::Aabb::CreateFromMinMax(currentMin, currentMax); + AZ::Vector3 previousMin = AZ::Vector3(m_detailTextureBounds.m_min.m_x * DetailTextureScale, m_detailTextureBounds.m_min.m_y * DetailTextureScale, -0.5f); + AZ::Vector3 previousMax = AZ::Vector3(m_detailTextureBounds.m_max.m_x * DetailTextureScale, m_detailTextureBounds.m_max.m_y * DetailTextureScale, 0.5f); + AZ::Aabb previousCoverage = AZ::Aabb::CreateFromMinMax(previousMin, previousMax); + + // Area of texture not already updated by camera movement above. + AZ::Aabb clampedCoverage = previousCoverage.GetClamped(detailTextureCoverage); + + // Clamp the dirty region to the area of the detail texture that is visible and not already updated. + clampedCoverage.Clamp(m_dirtyDetailRegion); + + if (clampedCoverage.IsValid()) + { + Aabb2i updateBounds; + updateBounds.m_min.m_x = aznumeric_cast(AZStd::roundf(clampedCoverage.GetMin().GetX() / DetailTextureScale)); + updateBounds.m_min.m_y = aznumeric_cast(AZStd::roundf(clampedCoverage.GetMin().GetY() / DetailTextureScale)); + updateBounds.m_max.m_x = aznumeric_cast(AZStd::roundf(clampedCoverage.GetMax().GetX() / DetailTextureScale)); + updateBounds.m_max.m_y = aznumeric_cast(AZStd::roundf(clampedCoverage.GetMax().GetY() / DetailTextureScale)); + if (updateBounds.m_min.m_x < updateBounds.m_max.m_x && updateBounds.m_min.m_y < updateBounds.m_max.m_y) + { + UpdateDetailTexture(updateBounds, newBounds, newCenter); + } + } + } + } + + } + + uint8_t TerrainFeatureProcessor::CalculateUpdateRegions(const Aabb2i& updateArea, const Aabb2i& textureBounds, const Vector2i& centerPixel, + AZStd::array& textureSpaceAreas, AZStd::array& scaledWorldSpaceAreas) + { + Vector2i centerOffset = { centerPixel.m_x - DetailTextureSizeHalf, centerPixel.m_y - DetailTextureSizeHalf }; + + int32_t quadrantXOffset = centerPixel.m_x < DetailTextureSizeHalf ? DetailTextureSize : -DetailTextureSize; + int32_t quadrantYOffset = centerPixel.m_y < DetailTextureSizeHalf ? DetailTextureSize : -DetailTextureSize; + + uint8_t numQuadrants = 0; + + // For each of the 4 quadrants: + auto calculateQuadrant = [&](Vector2i quadrantOffset) + { + Aabb2i offsetUpdateArea = updateArea + centerOffset + quadrantOffset; + Aabb2i updateSectionBounds = textureBounds.GetClamped(offsetUpdateArea); + if (updateSectionBounds.IsValid()) + { + textureSpaceAreas[numQuadrants] = updateSectionBounds - textureBounds.m_min; + scaledWorldSpaceAreas[numQuadrants] = updateSectionBounds - centerOffset - quadrantOffset; + ++numQuadrants; + } + }; + + calculateQuadrant({ 0, 0 }); + calculateQuadrant({ quadrantXOffset, 0 }); + calculateQuadrant({ 0, quadrantYOffset }); + calculateQuadrant({ quadrantXOffset, quadrantYOffset }); + + return numQuadrants; + } + + void TerrainFeatureProcessor::UpdateDetailTexture(const Aabb2i& updateArea, const Aabb2i& textureBounds, const Vector2i& centerPixel) + { + if (!m_detailTextureImage) + { + return; + } + + struct DetailMaterialPixel + { + uint8_t m_material1{ 255 }; + uint8_t m_material2{ 255 }; + uint8_t m_blend{ 0 }; // 0 = full weight on material1, 255 = full weight on material2 + uint8_t m_padding{ 0 }; + }; + + // Because the center of the detail texture may be offset, each update area may actually need to be split into + // up to 4 separate update areas in each sector of the quadrant. + AZStd::array textureSpaceAreas; + AZStd::array scaledWorldSpaceAreas; + uint8_t updateAreaCount = CalculateUpdateRegions(updateArea, textureBounds, centerPixel, textureSpaceAreas, scaledWorldSpaceAreas); + + // Pull the data for each area updated and use it to construct an update for the detail material id texture. + for (uint8_t i = 0; i < updateAreaCount; ++i) + { + const Aabb2i& quadrantTextureArea = textureSpaceAreas[i]; + const Aabb2i& quadrantWorldArea = scaledWorldSpaceAreas[i]; + + AZStd::vector pixels; + pixels.resize((quadrantWorldArea.m_max.m_x - quadrantWorldArea.m_min.m_x) * (quadrantWorldArea.m_max.m_y - quadrantWorldArea.m_min.m_y)); + uint32_t index = 0; + + for (int yPos = quadrantWorldArea.m_min.m_y; yPos < quadrantWorldArea.m_max.m_y; ++yPos) + { + for (int xPos = quadrantWorldArea.m_min.m_x; xPos < quadrantWorldArea.m_max.m_x; ++xPos) + { + AZ::Vector2 position = AZ::Vector2(xPos * DetailTextureScale, yPos * DetailTextureScale); + AzFramework::SurfaceData::SurfaceTagWeightList surfaceWeights; + AzFramework::Terrain::TerrainDataRequestBus::Broadcast(&AzFramework::Terrain::TerrainDataRequests::GetSurfaceWeightsFromVector2, position, surfaceWeights, AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, nullptr); + + // Store the top two surface weights in the texture with m_blend storing the relative weight. + bool isFirstMaterial = true; + float firstWeight = 0.0f; + for (const auto& surfaceTagWeight : surfaceWeights) + { + if (surfaceTagWeight.m_weight > 0.0f) + { + AZ::Crc32 surfaceType = surfaceTagWeight.m_surfaceType; + uint16_t materialId = GetDetailMaterialForSurfaceTypeAndPosition(surfaceType, position); + if (materialId != m_detailMaterials.NoFreeSlot && materialId < 255) + { + if (isFirstMaterial) + { + pixels.at(index).m_material1 = aznumeric_cast(materialId); + firstWeight = surfaceTagWeight.m_weight; + // m_blend only needs to be calculated is material 2 is found, otherwise the initial value of 0 is correct. + isFirstMaterial = false; + } + else + { + pixels.at(index).m_material2 = aznumeric_cast(materialId); + float totalWeight = firstWeight + surfaceTagWeight.m_weight; + float blendWeight = 1.0f - (firstWeight / totalWeight); + pixels.at(index).m_blend = aznumeric_cast(AZStd::round(blendWeight * 255.0f)); + break; + } + } + } + else + { + break; // since the list is ordered, no other materials are in the list with positive weights. + } + } + ++index; + } + } + + const int32_t left = quadrantTextureArea.m_min.m_x; + const int32_t top = quadrantTextureArea.m_min.m_y; + const int32_t width = quadrantTextureArea.m_max.m_x - quadrantTextureArea.m_min.m_x; + const int32_t height = quadrantTextureArea.m_max.m_y - quadrantTextureArea.m_min.m_y; + + AZ::RHI::ImageUpdateRequest imageUpdateRequest; + imageUpdateRequest.m_imageSubresourcePixelOffset.m_left = aznumeric_cast(left); + imageUpdateRequest.m_imageSubresourcePixelOffset.m_top = aznumeric_cast(top); + imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerRow = width * sizeof(DetailMaterialPixel); + imageUpdateRequest.m_sourceSubresourceLayout.m_bytesPerImage = width * height * sizeof(DetailMaterialPixel); + imageUpdateRequest.m_sourceSubresourceLayout.m_rowCount = height; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_width = width; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_height = height; + imageUpdateRequest.m_sourceSubresourceLayout.m_size.m_depth = 1; + imageUpdateRequest.m_sourceData = pixels.data(); + imageUpdateRequest.m_image = m_detailTextureImage->GetRHIImage(); + + m_detailTextureImage->UpdateImageContents(imageUpdateRequest); + } + } + + uint16_t TerrainFeatureProcessor::GetDetailMaterialForSurfaceTypeAndPosition(AZ::Crc32 surfaceType, const AZ::Vector2& position) + { + for (const auto& materialRegion : m_detailMaterialRegions.GetDataVector()) + { + if (materialRegion.m_region.Contains(AZ::Vector3(position.GetX(), position.GetY(), 0.0f))) + { + for (const auto& materialSurface : materialRegion.m_materialsForSurfaces) + { + if (materialSurface.m_surfaceTag == surfaceType) + { + return materialSurface.m_detailMaterialId; + } + } + } + } + return m_detailMaterials.NoFreeSlot; + } + + void TerrainFeatureProcessor::UpdateTerrainData() + { uint32_t width = m_areaData.m_updateWidth; uint32_t height = m_areaData.m_updateHeight; const AZ::Aabb& worldBounds = m_areaData.m_terrainBounds; @@ -280,8 +796,10 @@ namespace Terrain AZ::RHI::ImageDescriptor imageDescriptor = AZ::RHI::ImageDescriptor::Create2D( AZ::RHI::ImageBindFlags::ShaderRead, width, height, AZ::RHI::Format::R16_UNORM ); + + const AZ::Name TerrainHeightmapName = AZ::Name(TerrainHeightmapChars); m_areaData.m_heightmapImage = AZ::RPI::AttachmentImage::Create(*imagePool.get(), imageDescriptor, TerrainHeightmapName, nullptr, nullptr); - AZ_Error(TerrainFPName, m_areaData.m_heightmapImage, "Failed to initialize the heightmap image!"); + AZ_Error(TerrainFPName, m_areaData.m_heightmapImage, "Failed to initialize the heightmap image."); } AZStd::vector pixels; @@ -366,6 +884,19 @@ namespace Terrain m_heightmapPropertyIndex = m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::HeightmapImage)); AZ_Error(TerrainFPName, m_heightmapPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::HeightmapImage); + m_detailMaterialIdPropertyIndex = m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::DetailMaterialIdImage)); + AZ_Error(TerrainFPName, m_detailMaterialIdPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::DetailMaterialIdImage); + + m_detailCenterPropertyIndex = m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::DetailCenter)); + AZ_Error(TerrainFPName, m_detailCenterPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::DetailCenter); + + m_detailAabbPropertyIndex = m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::DetailAabb)); + AZ_Error(TerrainFPName, m_detailAabbPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::DetailAabb); + + m_detailHalfPixelUvPropertyIndex = m_materialInstance->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name(MaterialInputs::DetailHalfPixelUv)); + AZ_Error(TerrainFPName, m_detailHalfPixelUvPropertyIndex.IsValid(), "Failed to find material input constant %s.", MaterialInputs::DetailHalfPixelUv); + + // Find any macro materials that have already been created. TerrainMacroMaterialRequestBus::EnumerateHandlers( [&](TerrainMacroMaterialRequests* handler) { @@ -376,6 +907,30 @@ namespace Terrain } ); TerrainMacroMaterialNotificationBus::Handler::BusConnect(); + + // Find any detail material areas that have already been created. + TerrainAreaMaterialRequestBus::EnumerateHandlers( + [&](TerrainAreaMaterialRequests* handler) + { + const AZ::Aabb& bounds = handler->GetTerrainSurfaceMaterialRegion(); + const AZStd::vector materialMappings = handler->GetSurfaceMaterialMappings(); + AZ::EntityId entityId = *(Terrain::TerrainAreaMaterialRequestBus::GetCurrentBusId()); + + DetailMaterialListRegion& materialRegion = FindOrCreateByEntityId(entityId, m_detailMaterialRegions); + materialRegion.m_region = bounds; + + for (const auto& materialMapping : materialMappings) + { + if (materialMapping.m_materialInstance) + { + OnTerrainSurfaceMaterialMappingCreated(entityId, materialMapping.m_surfaceTag, materialMapping.m_materialInstance); + } + } + return true; + } + ); + TerrainAreaMaterialNotificationBus::Handler::BusConnect(); + } void TerrainFeatureProcessor::UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, const MacroMaterialData& newMaterialData) @@ -474,14 +1029,73 @@ namespace Terrain } } } + else if (m_forceRebuildDrawPackets) + { + for (auto& sectorData : m_sectorData) + { + for (auto& drawPacket : sectorData.m_drawPackets) + { + drawPacket.Update(*GetParentScene(), true); + } + } + } + m_forceRebuildDrawPackets = false; if (m_areaData.m_heightmapUpdated) { UpdateTerrainData(); - - const AZ::Data::Instance heightmapImage = m_areaData.m_heightmapImage; + + const AZ::Data::Instance heightmapImage = m_areaData.m_heightmapImage; // cast StreamingImage to Image m_materialInstance->SetPropertyValue(m_heightmapPropertyIndex, heightmapImage); - m_materialInstance->Compile(); + } + + AZ::Vector3 cameraPosition = AZ::Vector3::CreateZero(); + for (auto& view : process.m_views) + { + if ((view->GetUsageFlags() & AZ::RPI::View::UsageFlags::UsageCamera) > 0) + { + cameraPosition = view->GetCameraTransform().GetTranslation(); + break; + } + } + + if (m_dirtyDetailRegion.IsValid() || !cameraPosition.IsClose(m_previousCameraPosition)) + { + int32_t newDetailTexturePosX = aznumeric_cast(AZStd::roundf(cameraPosition.GetX() / DetailTextureScale)); + int32_t newDetailTexturePosY = aznumeric_cast(AZStd::roundf(cameraPosition.GetY() / DetailTextureScale)); + + Aabb2i newBounds; + newBounds.m_min.m_x = newDetailTexturePosX - DetailTextureSizeHalf; + newBounds.m_min.m_y = newDetailTexturePosY - DetailTextureSizeHalf; + newBounds.m_max.m_x = newDetailTexturePosX + DetailTextureSizeHalf; + newBounds.m_max.m_y = newDetailTexturePosY + DetailTextureSizeHalf; + + // Use modulo to find the center point in texture space. Care must be taken so negative values are + // handled appropriately (ie, we want -1 % 1024 to equal 1023, not -1) + Vector2i newCenter; + newCenter.m_x = (DetailTextureSize + (newDetailTexturePosX % DetailTextureSize)) % DetailTextureSize; + newCenter.m_y = (DetailTextureSize + (newDetailTexturePosY % DetailTextureSize)) % DetailTextureSize; + + CheckUpdateDetailTexture(newBounds, newCenter); + + m_detailTextureBounds = newBounds; + m_dirtyDetailRegion = AZ::Aabb::CreateNull(); + + m_previousCameraPosition = cameraPosition; + const AZ::Data::Instance detailTextureImage = m_detailTextureImage; // cast StreamingImage to Image + m_materialInstance->SetPropertyValue(m_detailMaterialIdPropertyIndex, detailTextureImage); + + AZ::Vector4 detailAabb = AZ::Vector4( + m_detailTextureBounds.m_min.m_x * DetailTextureScale, + m_detailTextureBounds.m_min.m_y * DetailTextureScale, + m_detailTextureBounds.m_max.m_x * DetailTextureScale, + m_detailTextureBounds.m_max.m_y * DetailTextureScale + ); + m_materialInstance->SetPropertyValue(m_detailAabbPropertyIndex, detailAabb); + m_materialInstance->SetPropertyValue(m_detailHalfPixelUvPropertyIndex, 0.5f / DetailTextureSize); + + AZ::Vector2 detailUvOffset = AZ::Vector2(float(newCenter.m_x) / DetailTextureSize, float(newCenter.m_y) / DetailTextureSize); + m_materialInstance->SetPropertyValue(m_detailCenterPropertyIndex, detailUvOffset); } if (m_areaData.m_heightmapUpdated || m_areaData.m_macroMaterialsUpdated) @@ -603,6 +1217,11 @@ namespace Terrain } } } + + if (m_materialInstance) + { + m_materialInstance->Compile(); + } } void TerrainFeatureProcessor::InitializeTerrainPatch(uint16_t gridSize, float gridSpacing, PatchData& patchdata) @@ -746,9 +1365,10 @@ namespace Terrain // larger but this will limit how much is rendered. } - MacroMaterialData* TerrainFeatureProcessor::FindMacroMaterial(AZ::EntityId entityId) + template + T* TerrainFeatureProcessor::FindByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector& container) { - for (MacroMaterialData& data : m_macroMaterials.GetDataVector()) + for (T& data : container.GetDataVector()) { if (data.m_entityId == entityId) { @@ -757,34 +1377,36 @@ namespace Terrain } return nullptr; } - - MacroMaterialData& TerrainFeatureProcessor::FindOrCreateMacroMaterial(AZ::EntityId entityId) + + template + T& TerrainFeatureProcessor::FindOrCreateByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector& container) { - MacroMaterialData* dataPtr = FindMacroMaterial(entityId); + T* dataPtr = FindByEntityId(entityId, container); if (dataPtr != nullptr) { return *dataPtr; } - const uint16_t slotId = m_macroMaterials.GetFreeSlotIndex(); - AZ_Assert(slotId != m_macroMaterials.NoFreeSlot, "Ran out of indices for macro materials"); + const uint16_t slotId = container.GetFreeSlotIndex(); + AZ_Assert(slotId != AZ::Render::IndexedDataVector::NoFreeSlot, "Ran out of indices"); - MacroMaterialData& data = m_macroMaterials.GetData(slotId); + T& data = container.GetData(slotId); data.m_entityId = entityId; return data; } - - void TerrainFeatureProcessor::RemoveMacroMaterial(AZ::EntityId entityId) + + template + void TerrainFeatureProcessor::RemoveByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector& container) { - for (MacroMaterialData& data : m_macroMaterials.GetDataVector()) + for (T& data : container.GetDataVector()) { if (data.m_entityId == entityId) { - m_macroMaterials.RemoveData(&data); + container.RemoveData(&data); return; } } - AZ_Assert(false, "Entity Id not found in m_macroMaterials.") + AZ_Assert(false, "Entity Id not found in container.") } template @@ -798,4 +1420,60 @@ namespace Terrain } } } + + auto TerrainFeatureProcessor::Vector2i::operator+(const Vector2i& rhs) const -> Vector2i + { + Vector2i offsetPoint = *this; + offsetPoint += rhs; + return offsetPoint; + } + + auto TerrainFeatureProcessor::Vector2i::operator+=(const Vector2i& rhs) -> Vector2i& + { + m_x += rhs.m_x; + m_y += rhs.m_y; + return *this; + } + + auto TerrainFeatureProcessor::Vector2i::operator-(const Vector2i& rhs) const -> Vector2i + { + return *this + -rhs; + } + + auto TerrainFeatureProcessor::Vector2i::operator-=(const Vector2i& rhs) -> Vector2i& + { + return *this += -rhs; + } + + auto TerrainFeatureProcessor::Vector2i::operator-() const -> Vector2i + { + return {-m_x, -m_y}; + } + + auto TerrainFeatureProcessor::Aabb2i::operator+(const Vector2i& rhs) const -> Aabb2i + { + return { m_min + rhs, m_max + rhs }; + } + + auto TerrainFeatureProcessor::Aabb2i::operator-(const Vector2i& rhs) const -> Aabb2i + { + return *this + -rhs; + } + + auto TerrainFeatureProcessor::Aabb2i::GetClamped(Aabb2i rhs) const -> Aabb2i + { + Aabb2i ret; + ret.m_min.m_x = AZ::GetMax(m_min.m_x, rhs.m_min.m_x); + ret.m_min.m_y = AZ::GetMax(m_min.m_y, rhs.m_min.m_y); + ret.m_max.m_x = AZ::GetMin(m_max.m_x, rhs.m_max.m_x); + ret.m_max.m_y = AZ::GetMin(m_max.m_y, rhs.m_max.m_y); + return ret; + } + + bool TerrainFeatureProcessor::Aabb2i::IsValid() const + { + // Intentionally strict, equal min/max not valid. + return m_min.m_x < m_max.m_x && m_min.m_y < m_max.m_y; + } + } diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h index f82fd8ecb0..962ffe13bf 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h @@ -12,11 +12,13 @@ #include #include +#include #include #include #include #include +#include #include namespace AZ::RPI @@ -37,6 +39,7 @@ namespace Terrain , private AZ::RPI::MaterialReloadNotificationBus::Handler , private AzFramework::Terrain::TerrainDataNotificationBus::Handler , private TerrainMacroMaterialNotificationBus::Handler + , private TerrainAreaMaterialNotificationBus::Handler { public: AZ_RTTI(TerrainFeatureProcessor, "{D7DAC1F9-4A9F-4D3C-80AE-99579BF8AB1C}", AZ::RPI::FeatureProcessor); @@ -112,6 +115,109 @@ namespace Terrain AZStd::fixed_vector m_macroMaterials; }; + enum DetailTextureFlags : uint32_t + { + UseTextureBaseColor = 0b0000'0000'0000'0000'0000'0000'0000'0001, + UseTextureNormal = 0b0000'0000'0000'0000'0000'0000'0000'0010, + UseTextureMetallic = 0b0000'0000'0000'0000'0000'0000'0000'0100, + UseTextureRoughness = 0b0000'0000'0000'0000'0000'0000'0000'1000, + UseTextureOcclusion = 0b0000'0000'0000'0000'0000'0000'0001'0000, + UseTextureHeight = 0b0000'0000'0000'0000'0000'0000'0010'0000, + UseTextureSpecularF0 = 0b0000'0000'0000'0000'0000'0000'0100'0000, + + FlipNormalX = 0b0000'0000'0000'0000'0000'0000'1000'0000, + FlipNormalY = 0b0000'0000'0000'0000'0000'0001'0000'0000, + + BlendModeMask = 0b0000'0000'0000'0000'0000'0110'0000'0000, + BlendModeLerp = 0b0000'0000'0000'0000'0000'0000'0000'0000, + BlendModeLinearLight = 0b0000'0000'0000'0000'0000'0010'0000'0000, + BlendModeMultiply = 0b0000'0000'0000'0000'0000'0100'0000'0000, + BlendModeOverlay = 0b0000'0000'0000'0000'0000'0110'0000'0000, + }; + + struct DetailMaterialShaderProperties + { + // Uv + AZStd::array m_uvTransform + { + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + }; + + // Factor / Scale / Bias for input textures + float m_baseColorFactor{ 1.0f }; + float m_normalFactor{ 1.0f }; + float m_metalFactor{ 1.0f }; + float m_roughnessScale{ 1.0f }; + + float m_roughnessBias{ 0.0f }; + float m_specularF0Factor{ 1.0f }; + float m_occlusionFactor{ 1.0f }; + float m_heightFactor{ 1.0f }; + + float m_heightOffset{ 0.0f }; + float m_heightBlendFactor{ 0.5f }; + + // Flags + DetailTextureFlags m_flags{ 0 }; + + float m_padding; // 16 byte aligned + }; + + struct DetailMaterialData + { + AZ::Data::AssetId m_assetId; + AZ::RPI::Material::ChangeId m_materialChangeId{AZ::RPI::Material::DEFAULT_CHANGE_ID}; + + AZ::Data::Instance m_colorImage; + AZ::Data::Instance m_normalImage; + AZ::Data::Instance m_roughnessImage; + AZ::Data::Instance m_metalnessImage; + AZ::Data::Instance m_specularF0Image; + AZ::Data::Instance m_occlusionImage; + AZ::Data::Instance m_heightImage; + + DetailMaterialShaderProperties m_properties; // maps directly to shader + }; + + struct DetailMaterialSurface + { + AZ::Crc32 m_surfaceTag; + uint16_t m_detailMaterialId; + }; + + struct DetailMaterialListRegion + { + AZ::EntityId m_entityId; + AZ::Aabb m_region{AZ::Aabb::CreateNull()}; + AZStd::vector m_materialsForSurfaces; + }; + + struct Vector2i + { + int32_t m_x{ 0 }; + int32_t m_y{ 0 }; + + Vector2i operator+(const Vector2i& rhs) const; + Vector2i& operator+=(const Vector2i& rhs); + Vector2i operator-(const Vector2i& rhs) const; + Vector2i& operator-=(const Vector2i& rhs); + Vector2i operator-() const; + }; + + struct Aabb2i + { + Vector2i m_min; + Vector2i m_max; + + Aabb2i operator+(const Vector2i& offset) const; + Aabb2i operator-(const Vector2i& offset) const; + + Aabb2i GetClamped(Aabb2i rhs) const; + bool IsValid() const; + }; + // AZ::RPI::MaterialReloadNotificationBus::Handler overrides... void OnMaterialReinitialized(const MaterialInstance& material) override; @@ -124,6 +230,12 @@ namespace Terrain void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& material) override; void OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override; void OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) override; + + // TerrainAreaMaterialNotificationBus overrides... + void OnTerrainSurfaceMaterialMappingCreated(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, MaterialInstance material) override; + void OnTerrainSurfaceMaterialMappingDestroyed(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag) override; + void OnTerrainSurfaceMaterialMappingChanged(AZ::EntityId entityId, SurfaceData::SurfaceTag surfaceTag, MaterialInstance material) override; + void OnTerrainSurfaceMaterialMappingRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override; void Initialize(); void InitializeTerrainPatch(uint16_t gridSize, float gridSpacing, PatchData& patchdata); @@ -132,12 +244,26 @@ namespace Terrain void UpdateTerrainData(); void PrepareMaterialData(); void UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, const MacroMaterialData& newMaterialData); + + void TerrainHeightOrSettingsUpdated(const AZ::Aabb& dirtyRegion); + void TerrainSurfaceDataUpdated(const AZ::Aabb& dirtyRegion); + + uint16_t CreateOrUpdateDetailMaterial(MaterialInstance material); + void UpdateDetailMaterialData(DetailMaterialData& materialData, MaterialInstance material); + void CheckUpdateDetailTexture(const Aabb2i& newBounds, const Vector2i& newCenter); + void UpdateDetailTexture(const Aabb2i& updateArea, const Aabb2i& textureBounds, const Vector2i& centerPixel); + uint16_t GetDetailMaterialForSurfaceTypeAndPosition(AZ::Crc32 surfaceType, const AZ::Vector2& position); + uint8_t CalculateUpdateRegions(const Aabb2i& updateArea, const Aabb2i& textureBounds, const Vector2i& centerPixel, + AZStd::array& textureSpaceAreas, AZStd::array& scaledWorldSpaceAreas); void ProcessSurfaces(const FeatureProcessor::RenderPacket& process); - - MacroMaterialData* FindMacroMaterial(AZ::EntityId entityId); - MacroMaterialData& FindOrCreateMacroMaterial(AZ::EntityId entityId); - void RemoveMacroMaterial(AZ::EntityId entityId); + + template + T* FindByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector& container); + template + T& FindOrCreateByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector& container); + template + void RemoveByEntityId(AZ::EntityId entityId, AZ::Render::IndexedDataVector& container); template void ForOverlappingSectors(const AZ::Aabb& bounds, Callback callback); @@ -147,8 +273,11 @@ namespace Terrain // System-level parameters static constexpr float GridSpacing{ 1.0f }; - static constexpr uint32_t GridSize{ 64 }; // number of terrain quads (vertices are m_gridSize + 1) + static constexpr int32_t GridSize{ 64 }; // number of terrain quads (vertices are m_gridSize + 1) static constexpr float GridMeters{ GridSpacing * GridSize }; + static constexpr int32_t DetailTextureSize{ 1024 }; + static constexpr int32_t DetailTextureSizeHalf{ DetailTextureSize / 2 }; + static constexpr float DetailTextureScale{ 0.5f }; AZStd::unique_ptr m_materialAssetLoader; MaterialInstance m_materialInstance; @@ -160,8 +289,13 @@ namespace Terrain AZ::RHI::ShaderInputImageIndex m_macroColorMapIndex; AZ::RHI::ShaderInputImageIndex m_macroNormalMapIndex; AZ::RPI::MaterialPropertyIndex m_heightmapPropertyIndex; + AZ::RPI::MaterialPropertyIndex m_detailMaterialIdPropertyIndex; + AZ::RPI::MaterialPropertyIndex m_detailCenterPropertyIndex; + AZ::RPI::MaterialPropertyIndex m_detailAabbPropertyIndex; + AZ::RPI::MaterialPropertyIndex m_detailHalfPixelUvPropertyIndex; AZ::Data::Instance m_patchModel; + AZ::Vector3 m_previousCameraPosition = AZ::Vector3(AZStd::numeric_limits::max(), 0.0, 0.0); // Per-area data struct TerrainAreaData @@ -178,12 +312,21 @@ namespace Terrain bool m_macroMaterialsUpdated{ true }; bool m_rebuildSectors{ true }; }; - + TerrainAreaData m_areaData; AZ::Aabb m_dirtyRegion{ AZ::Aabb::CreateNull() }; + AZ::Aabb m_dirtyDetailRegion{ AZ::Aabb::CreateNull() }; + + Aabb2i m_detailTextureBounds; + Vector2i m_detailTextureCenter; + AZ::Data::Instance m_detailTextureImage; + AZ::RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler m_handleGlobalShaderOptionUpdate; + bool m_forceRebuildDrawPackets = false; AZStd::vector m_sectorData; AZ::Render::IndexedDataVector m_macroMaterials; + AZ::Render::IndexedDataVector m_detailMaterials; + AZ::Render::IndexedDataVector m_detailMaterialRegions; }; } From 3dea8fc03d54ea83f4c5b25d47ae2a098190c736 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Wed, 27 Oct 2021 08:46:31 -0700 Subject: [PATCH 084/200] Add Generic DOM visitor interface (#4852) * Add Generic DOM visitor interface Just the visitor interface from the [Generic DOM RFC](https://github.com/o3de/sig-content/blob/main/rfcs/rfc-10-generic-dom.md) with a few hardening changes so that we can align on it early: - Clarified Lifetimes with an enum, extended it to cover the by-ref opaque values as well - Added an explicit error type so that serializers can provide logging friendly rejections - Did a first pass on documentation - Added Visitor capabilities introspection and support for raw strings Signed-off-by: Gene Walters --- .../AzCore/AzCore/DOM/DomVisitor.cpp | 239 ++++++++++++++++++ Code/Framework/AzCore/AzCore/DOM/DomVisitor.h | 237 +++++++++++++++++ .../AzCore/AzCore/azcore_files.cmake | 2 + 3 files changed, 478 insertions(+) create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomVisitor.h diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp new file mode 100644 index 0000000000..5d66bb6ac5 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.cpp @@ -0,0 +1,239 @@ +/* + * 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 + +namespace AZ::DOM +{ + const char* VisitorError::CodeToString(VisitorErrorCode code) + { + switch (code) + { + case VisitorErrorCode::UnsupportedOperation: + return "operation not supported"; + case VisitorErrorCode::InvalidData: + return "invalid data specified"; + case VisitorErrorCode::InternalError: + return "internal error"; + default: + return "unknown error"; + } + } + + VisitorError::VisitorError(VisitorErrorCode code) + : m_code(code) + { + } + + VisitorError::VisitorError(VisitorErrorCode code, AZStd::string additionalInfo) + : m_code(code) + , m_additionalInfo(AZStd::move(additionalInfo)) + { + } + + VisitorErrorCode VisitorError::GetCode() const + { + return m_code; + } + + const AZStd::string& VisitorError::GetAdditionalInfo() const + { + return m_additionalInfo; + } + + AZStd::string VisitorError::FormatVisitorErrorMessage() const + { + if (m_additionalInfo.empty()) + { + return AZStd::string::format("VisitorError: %s.", CodeToString(m_code)); + } + return AZStd::string::format("VisitorError: %s. %s.", CodeToString(m_code), m_additionalInfo.c_str()); + } + + Visitor::Result Visitor::VisitorFailure(VisitorErrorCode code) + { + return AZ::Failure(VisitorError(code)); + } + + Visitor::Result Visitor::VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo) + { + return AZ::Failure(VisitorError(code, AZStd::move(additionalInfo))); + } + + Visitor::Result Visitor::VisitorFailure(VisitorError error) + { + return AZ::Failure(error); + } + + Visitor::Result Visitor::VisitorSuccess() + { + return AZ::Success(); + } + + Visitor::Result Visitor::Null() + { + return VisitorSuccess(); + } + + Visitor::Result Visitor::Bool([[maybe_unused]] bool value) + { + return VisitorSuccess(); + } + + Visitor::Result Visitor::Int64([[maybe_unused]] AZ::s64 value) + { + return VisitorSuccess(); + } + + Visitor::Result Visitor::Uint64([[maybe_unused]] AZ::u64 value) + { + return VisitorSuccess(); + } + + Visitor::Result Visitor::Double([[maybe_unused]] double value) + { + return VisitorSuccess(); + } + + Visitor::Result Visitor::String([[maybe_unused]] AZStd::string_view value, [[maybe_unused]] Lifetime lifetime) + { + return VisitorSuccess(); + } + + Visitor::Result Visitor::OpaqueValue([[maybe_unused]] const OpaqueType& value, [[maybe_unused]] Lifetime lifetime) + { + if (!SupportsOpaqueValues()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Opaque values are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::RawValue([[maybe_unused]] AZStd::string_view value, [[maybe_unused]] Lifetime lifetime) + { + if (!SupportsRawValues()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Raw values are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::StartObject() + { + if (!SupportsObjects()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Objects are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::EndObject([[maybe_unused]] AZ::u64 attributeCount) + { + if (!SupportsObjects()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Objects are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::Key([[maybe_unused]] AZ::Name key) + { + if (!SupportsObjects() && !SupportsNodes()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Keys are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::RawKey(AZStd::string_view key, [[maybe_unused]] Lifetime lifetime) + { + if (!SupportsRawKeys()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Raw keys are not supported by this visitor"); + } + return Key(AZ::Name(key)); + } + + Visitor::Result Visitor::StartArray() + { + if (!SupportsArrays()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Arrays are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::EndArray([[maybe_unused]] AZ::u64 elementCount) + { + if (!SupportsArrays()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Arrays are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::StartNode([[maybe_unused]] AZ::Name name) + { + if (!SupportsNodes()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Nodes are not supported by this visitor"); + } + return VisitorSuccess(); + } + + Visitor::Result Visitor::RawStartNode(AZStd::string_view name, [[maybe_unused]] Lifetime lifetime) + { + return StartNode(AZ::Name(name)); + } + + Visitor::Result Visitor::EndNode([[maybe_unused]] AZ::u64 attributeCount, [[maybe_unused]] AZ::u64 elementCount) + { + if (!SupportsNodes()) + { + return VisitorFailure(VisitorErrorCode::UnsupportedOperation, "Nodes are not supported by this visitor"); + } + return VisitorSuccess(); + } + + VisitorFlags Visitor::GetVisitorFlags() const + { + // By default support raw keys (promoting them to AZ::Name) and support Array / Object / Node + // We leave Opaque type support and Raw Values to more specialized, implementation-specific cases + return VisitorFlags::SupportsRawKeys | VisitorFlags::SupportsArrays | VisitorFlags::SupportsObjects | VisitorFlags::SupportsNodes; + } + + bool Visitor::SupportsRawValues() const + { + return (GetVisitorFlags() & VisitorFlags::SupportsRawValues) != VisitorFlags::Null; + } + + bool Visitor::SupportsRawKeys() const + { + return (GetVisitorFlags() & VisitorFlags::SupportsRawKeys) != VisitorFlags::Null; + } + + bool Visitor::SupportsObjects() const + { + return (GetVisitorFlags() & VisitorFlags::SupportsObjects) != VisitorFlags::Null; + } + + bool Visitor::SupportsArrays() const + { + return (GetVisitorFlags() & VisitorFlags::SupportsArrays) != VisitorFlags::Null; + } + + bool Visitor::SupportsNodes() const + { + return (GetVisitorFlags() & VisitorFlags::SupportsNodes) != VisitorFlags::Null; + } + + bool Visitor::SupportsOpaqueValues() const + { + return (GetVisitorFlags() & VisitorFlags::SupportsOpaqueValues) != VisitorFlags::Null; + } +} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h new file mode 100644 index 0000000000..584cfce4ed --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomVisitor.h @@ -0,0 +1,237 @@ +/* + * 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 + +#include +#include +#include +#include + +namespace AZ::DOM +{ + // + // Lifetime enum + // + //! Specifies the period in which a reference value will still be alive and safe to read. + enum class Lifetime + { + //! Specifies that the value is safe to read and will remain so indefinitely. + //! This implies that the value will not be mutated for the duration of this storage. + Persistent, + //! Specifies that the value may change or be deallocated, and must be copied to be safely stored. + Temporary, + }; + + // + // VisitorErrorCode enum + // + //! Error code specifying the reason a Visitor operation failed. + enum class VisitorErrorCode + { + //! Set when a Visitor doesn't have an implementation for a given attribute type. + //! A pure-JSON serializer might reject a Node attribute, for example, and serialization visitors + //! can forbid non-serializable Opaque types. + UnsupportedOperation, + //! Set when a Visitor has received malformed or invalid data. + //! Potential sources include mismatching Begin/End call pairs or invalid attribute or element counts + //! being sent to End methods. + InvalidData, + //! The Visitor failed for some other reason not caused by invalid input. + //! If returning a custom error with this code, it's preferrable to also provide supplemental info + //! in the form of an explanatory string. + InternalError + }; + + // + // VisitorError class + // + //! Details of the reason for failure within a VisitorInterface operation. + class VisitorError final + { + public: + explicit VisitorError(VisitorErrorCode code); + VisitorError(VisitorErrorCode code, AZStd::string additionalInfo); + + //! Gets the error code associated with this error. + VisitorErrorCode GetCode() const; + //! Gets a supplemental error info string from the error. + //! Returns an empty string if no additional information was provided to the error. + const AZStd::string& GetAdditionalInfo() const; + //! Provides a formatted, human-readable error description that can be used for logging purposes. + AZStd::string FormatVisitorErrorMessage() const; + + //! Helper method, translates a VisitorErrorCode to a human readable string. + static const char* CodeToString(VisitorErrorCode code); + + private: + VisitorErrorCode m_code; + AZStd::string m_additionalInfo; + }; + + //! A type alias for opaque DOM types that aren't meant to be serializable. + //! /see VisitorInterface::OpaqueValue + using OpaqueType = AZStd::any; + + // + // VisitorFlags enum + // + //! Flags representning capabilities of a \ref Visitor. + enum class VisitorFlags : AZ::u16 + { + //! No flags are set. This can be used in conjunction with bitwise operators to check a flag. + Null = 0, + //! If set, this Visitor interface supports raw strings in place of specific value types. + //! Visitors with this flag accept RawValue calls in lieu of more specific value calls such as Int64 or String. + SupportsRawValues = (1 << 1), + //! If set, this Visitor interface supports raw strings in place of Name types for keys and Node names. + //! Visitors with this flag accept RawKey and RawStartNode in lieu of Key and StartNode calls. + SupportsRawKeys = (1 << 2), + //! If set, this Visitor interface supports Object types described via BeginObject and EndObject. + SupportsObjects = (1 << 3), + //! If set, this Visitor interface supports Array types described via BeginArray and EndArray. + SupportsArrays = (1 << 4), + //! If set, this Visitor interface supports Node types described BeginNode and EndNode. + SupportsNodes = (1 << 4), + //! If set, this Visitor interface supports opaque values described via OpaqueValue. + SupportsOpaqueValues = (1 << 5), + }; + + AZ_DEFINE_ENUM_BITWISE_OPERATORS(VisitorFlags); + + // + // Visitor class + // + //! An interface for performing operations on elements of a generic DOM (Document Object Model). + //! A Document Object Model is defined here as a tree structure comprised of one of the following values: + //! - Primitives: plain data types, including + //! - \ref Int64: 64 bit signed integer + //! - \ref Uint64: 64 bit unsigned integer + //! - \ref Bool: boolean value + //! - \ref Double: 64 bit double precision float + //! - \ref Null: sentinel "empty" type with no value representation + //! - \ref String: UTF8 encoded string + //! - \ref Object: an ordered container of key/value pairs where keys are AZ::Names and values may be any DOM type + //! (including Object) + //! - \ref Array: an ordered container of values, in which values are any DOM value type (including Array) + //! - \ref Node: a container + //! - \ref OpaqueValue: An arbitrary value stored in an AZStd::any. This is a non-serializable representation of an + //! entry useful for in-memory options. This is intended to be used as an intermediate value over the course of DOM + //! transformation and as a proxy to pass through types of which the DOM has no knowledge to other systems. + //! + //! Opaque values are rejected by the default VisitorInterface implementation. + //! + //! Care should be ensured that DOMs representing opaque types are only visited by consumers that understand them. + class Visitor + { + public: + virtual ~Visitor() = default; + + //! The result of a Visitor operation. + //! A failure indicates a non-recoverable issue and signals that no further visit calls may be made in the + //! current state. + using Result = AZ::Outcome; + + //! Returns a set of flags representing the operations this Visitor supports. + //! The base implementation supports raw keys (\see VisitorFlags::SupportsRawKeys) and + //! arrays (\see VisitorFlags::SupportsArrays), objects (\see VisitorFlags::SupportsObjects), and + //! nodes (\see VisitorFlags::SupportsNodes). + //! Raw (\see VisitorFlags::SupportsRawValues) and opaque values (\see VisitorFlags::SupportsOpaqueValues) + //! are disallowed by default, as their handling is intended to be implementation-specific. + virtual VisitorFlags GetVisitorFlags() const; + //! /see VisitorFlags::SupportsRawValues + bool SupportsRawValues() const; + //! /see VisitorFlags::SupportsRawKeys + bool SupportsRawKeys() const; + //! /see VisitorFlags::SupportsObjects + bool SupportsObjects() const; + //! /see VisitorFlags::SupportsArrays + bool SupportsArrays() const; + //! /see VisitorFlags::SupportsNodes + bool SupportsNodes() const; + //! /see VisitorFlags::SupportsOpaqueValues + bool SupportsOpaqueValues() const; + + //! Operates on an empty null value. + virtual Result Null(); + //! Operates on a bool value. + virtual Result Bool(bool value); + //! Operates on a signed, 64 bit integer value. + virtual Result Int64(AZ::s64 value); + //! Operates on an unsigned, 64 bit integer value. + virtual Result Uint64(AZ::u64 value); + //! Operates on a double precision, 64 bit floating point value. + virtual Result Double(double value); + //! Operates on a string value. As strings are a reference type. + //! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy. + virtual Result String(AZStd::string_view value, Lifetime lifetime); + //! Operates on an opaque value. As opaque values are a reference type, storage semantics are provided to + //! indicate where the value may be stored persistently or requires a copy. + //! The base implementation of OpaqueValue rejects the operation, as opaque values are meant for special + //! cases with specific implementations, not generic usage. + //! Storage semantics are provided to indicate where the value may be stored persistently or requires a copy. + virtual Result OpaqueValue(const OpaqueType& value, Lifetime lifetime); + //! Operates on a raw value encoded as a UTF-8 string that hasn't had its type deduced. + //! Visitors that support raw values (\see VisitorFlags::SupportsRawValues) may parse the raw value and + //! forward it to the corresponding value call or calls of their choice. + //! The base implementation of RawValue rejects the operation, as raw values are meant to be handled on + //! a per-implementation basis. + virtual Result RawValue(AZStd::string_view value, Lifetime lifetime); + + //! Operates on an Object. + //! Callers may make any number of Key calls, followed by calls representing a value (including a nested + //! StartObject call) and then must call EndObject. + virtual Result StartObject(); + //! Finishes operating on an Object. + //! Callers must provide the number of attributes that were provided to the object, i.e. the number of key + //! and value calls made within the direct context of this object (but not any nested objects / nodes). + virtual Result EndObject(AZ::u64 attributeCount); + + //! Specifies a key for a key/value pair. + //! Key must be called subsequent to a call to \ref StartObject or \ref StartNode and immediately followed by + //! calls representing the key's associated value. + virtual Result Key(AZ::Name key); + //! Specifies a key for a key/value pair using a raw string instead of \ref AZ::Name. + //! \see Key + virtual Result RawKey(AZStd::string_view key, Lifetime lifetime); + + //! Operates on an Array. + //! Callers may make any number of subsequent value calls to represent the elements of the array, and then must + //! call EndArray. + virtual Result StartArray(); + //! Finishes operating on an Array. + //! Callers must provide the number of elements that were provided to the array, i.e. the number of value calls + //! made within the direct context of this array (but not any nested arrays / nodes). + virtual Result EndArray(AZ::u64 elementCount); + + //! Operates on a Node. + //! Callers may make any number of Key calls followed by value calls or value calls not prefixed with a Key + //! call, and then must call EndNode. See \ref StartObject and \ref StartArray as Node types combine the + //! functionality of both structures into a named Node structure. + virtual Result StartNode(AZ::Name name); + //! Operates on a Node using a raw string instead of \ref AZ::Name. + //! \see StartNode + virtual Result RawStartNode(AZStd::string_view name, Lifetime lifetime); + //! Finishes operating on a Node. + //! Callers must provide both the number of attributes the were provided and the number of elements that were + //! provided to the node, attributes being values prefaced by a call to Key. + virtual Result EndNode(AZ::u64 attributeCount, AZ::u64 elementCount); + + protected: + Visitor() = default; + + //! Helper method, constructs a failure \ref Result with the specified code. + static Result VisitorFailure(VisitorErrorCode code); + //! Helper method, constructs a failure \ref Result with the specified code and supplemental info. + static Result VisitorFailure(VisitorErrorCode code, AZStd::string additionalInfo); + //! Helper method, constructs a failure \ref Result with the specified error. + static Result VisitorFailure(VisitorError error); + //! Helper method, constructs a success \ref Result. + static Result VisitorSuccess(); + }; +} // namespace AZ::DOM diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 0c5a360844..6a9e5a29d6 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -123,6 +123,8 @@ set(FILES Debug/TraceMessagesDrillerBus.h Debug/TraceReflection.cpp Debug/TraceReflection.h + DOM/DomVisitor.cpp + DOM/DomVisitor.h Driller/DefaultStringPool.h Driller/Driller.cpp Driller/Driller.h From bf958686c931b38fd3064608a8d251aacee09641 Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 26 Oct 2021 14:58:34 -0700 Subject: [PATCH 085/200] Calculate camera view projection each frame so we can have a fixed size viewport. Signed-off-by: rhhong Signed-off-by: Gene Walters --- .../Tools/EMStudio/AnimViewportRenderer.cpp | 4 ++-- .../Tools/EMStudio/AnimViewportWidget.cpp | 24 ++++++++++++++++++- .../Code/Tools/EMStudio/AnimViewportWidget.h | 3 +++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index f6186be235..facf7a7b12 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -128,10 +128,10 @@ namespace EMStudio AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); AZ::Render::GridComponentConfig gridConfig; - gridConfig.m_gridSize = 4.0f; + gridConfig.m_gridSize = 20.0f; gridConfig.m_axisColor = AZ::Color(0.5f, 0.5f, 0.5f, 1.0f); gridConfig.m_primaryColor = AZ::Color(0.3f, 0.3f, 0.3f, 1.0f); - gridConfig.m_secondaryColor = AZ::Color(0.5f, 0.1f, 0.1f, 1.0f); + gridConfig.m_secondaryColor = AZ::Color(0.5f, 0.5f, 0.5f, 1.0f); auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); gridComponent->SetConfiguration(gridConfig); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 7af5c1607a..42bc154fdf 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -6,10 +6,11 @@ * */ -#include +#include #include #include #include +#include #include #include @@ -19,6 +20,9 @@ namespace EMStudio { + static constexpr float DepthNear = 0.01f; + static constexpr float DepthFar = 100.0f; + AnimViewportWidget::AnimViewportWidget(QWidget* parent) : AtomToolsFramework::RenderViewportWidget(parent) { @@ -166,6 +170,24 @@ namespace EMStudio GetViewportContext()->SetCameraTransform(AZ::Transform::CreateLookAt(cameraPosition, targetPosition)); } + void AnimViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time) + { + RenderViewportWidget::OnTick(deltaTime, time); + CalculateCameraProjection(); + } + + void AnimViewportWidget::CalculateCameraProjection() + { + auto viewportContext = GetViewportContext(); + auto windowSize = viewportContext->GetViewportSize(); + const float aspectRatio = aznumeric_cast(windowSize.m_width) / aznumeric_cast(windowSize.m_height); + + AZ::Matrix4x4 viewToClipMatrix; + AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, aspectRatio, DepthNear, DepthFar, true); + + viewportContext->GetDefaultView()->SetViewToClipMatrix(viewToClipMatrix); + } + void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) { m_renderFlags[flag] = !m_renderFlags[flag]; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 8aa316a8ba..5a193d31f1 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -30,6 +30,9 @@ namespace EMStudio EMotionFX::ActorRenderFlagBitset GetRenderFlags() const; private: + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + void CalculateCameraProjection(); void SetupCameras(); void SetupCameraController(); From a803cdcbb34fd1f811bf564a578d26e1817ff7e8 Mon Sep 17 00:00:00 2001 From: rhhong Date: Wed, 27 Oct 2021 10:18:24 -0700 Subject: [PATCH 086/200] Fix build error Signed-off-by: rhhong Signed-off-by: Gene Walters --- .../Code/Tools/EMStudio/AnimViewportWidget.cpp | 7 +++---- .../EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index 42bc154fdf..c6e349236f 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -20,9 +20,6 @@ namespace EMStudio { - static constexpr float DepthNear = 0.01f; - static constexpr float DepthFar = 100.0f; - AnimViewportWidget::AnimViewportWidget(QWidget* parent) : AtomToolsFramework::RenderViewportWidget(parent) { @@ -180,7 +177,9 @@ namespace EMStudio { auto viewportContext = GetViewportContext(); auto windowSize = viewportContext->GetViewportSize(); - const float aspectRatio = aznumeric_cast(windowSize.m_width) / aznumeric_cast(windowSize.m_height); + // Prevent devided by zero + const float height = AZStd::max(aznumeric_cast(windowSize.m_height), 1.0f); + const float aspectRatio = aznumeric_cast(windowSize.m_width) / height; AZ::Matrix4x4 viewToClipMatrix; AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, aspectRatio, DepthNear, DepthFar, true); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 5a193d31f1..e2099ea2ab 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -45,6 +45,8 @@ namespace EMStudio void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag); static constexpr float CameraDistance = 2.0f; + static constexpr float DepthNear = 0.01f; + static constexpr float DepthFar = 100.0f; AZStd::unique_ptr m_renderer; AZStd::shared_ptr m_rotateCamera; From 131c415404a5285e3ef26b936ab6dec20706f3db Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 27 Oct 2021 16:07:53 -0700 Subject: [PATCH 087/200] small fix: adding newline back to end of a merged file Signed-off-by: Gene Walters --- AutomatedTesting/Gem/PythonTests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index fa13aee9d0..bec49185bd 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -63,4 +63,4 @@ add_subdirectory(AWS) add_subdirectory(Multiplayer) ## Integration tests for editor testing framework ## -add_subdirectory(editor_test_testing) \ No newline at end of file +add_subdirectory(editor_test_testing) From 013beafe7e6eb69d79eab7ed8239546c27371d6a Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 27 Oct 2021 16:23:24 -0700 Subject: [PATCH 088/200] Minor code warning grammar fix Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index adab2ae8d3..8145c61e87 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -57,7 +57,7 @@ namespace Multiplayer return networkEntityManager->GetEntityCount() > 0; } - AZ_Warning("MultiplayerEditorSystemComponent", false, "PyIsInGameMode returning false; no NetworkEntityManager has not been created yet."); + AZ_Warning("MultiplayerEditorSystemComponent", false, "PyIsInGameMode returning false; NetworkEntityManager has not been created yet.") return false; } From b324b3a1a994e00ac6b8e67f7e365870be07fab8 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 27 Oct 2021 16:28:51 -0700 Subject: [PATCH 089/200] Minor code comment grammar change Signed-off-by: Gene Walters --- .../Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h b/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h index 90f968f591..82b63d94f0 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Editor/MultiplayerPythonEditorEventsBus.h @@ -24,7 +24,7 @@ namespace Multiplayer virtual void EnterGameMode() = 0; /* - * Queries if it's in the game mode and the server has finished connecting and the default network player has spawned. + * Queries if the Editor is in game mode, the editor-server has finished connecting, and the default network player has spawned. */ virtual bool IsInGameMode() = 0; }; From bd6153f4719e1c890b81fa44ef81b08b66ea7d61 Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Thu, 28 Oct 2021 13:24:49 -0400 Subject: [PATCH 090/200] Material - enbale/disable metallic scale according to texture selection Remark: resolves GitHub issue https://github.com/o3de/o3de/issues/2647 - ATOM-15614 Signed-off-by: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> --- .../Materials/Types/EnhancedPBR.materialtype | 15 +++--- .../Types/StandardMultilayerPBR.materialtype | 46 +++++++------------ .../Materials/Types/StandardPBR.materialtype | 15 +++--- .../Materials/Types/StandardPBR_Metallic.lua | 43 +++++++++++++++++ 4 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_Metallic.lua 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 From fc94ede4398b9d8b6f96ecdc63ad0f158cf7f2c4 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 28 Oct 2021 11:55:49 -0700 Subject: [PATCH 091/200] [profiler_capture_api] fixed runtime issues with BehaviorInterfaceProxy reflection Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../AzCore/Debug/ProfilerReflection.cpp | 10 +++- .../AzCore/RTTI/BehaviorInterfaceProxy.h | 58 ++++++++++--------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp index 430e320c54..3455400cfe 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp @@ -51,13 +51,15 @@ namespace AZ::Debug { 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::GetInstance) + behaviorContext->ConstantProperty("g_ProfilerSystem", ProfilerSystemScriptProxy::GetProxy) ->Attribute(AZ::Script::Attributes::Category, ProfilerScriptCategory) ->Attribute(AZ::Script::Attributes::Module, ProfilerScriptModule) ->Attribute(AZ::Script::Attributes::Scope, ProfilerScriptScope); @@ -69,6 +71,12 @@ namespace AZ::Debug ->Method("IsValid", &ProfilerSystemScriptProxy::IsValid) + ->Method("GetCaptureLocation", + [](ProfilerSystemScriptProxy*) -> AZStd::string + { + return AZStd::string(GetProfilerCaptureLocation().c_str()); + }) + ->Method("IsActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::IsActive>()) ->Method("SetActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::SetActive>()) diff --git a/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h index 430524d3a2..0e7a4ac356 100644 --- a/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h +++ b/Code/Framework/AzCore/AzCore/RTTI/BehaviorInterfaceProxy.h @@ -34,13 +34,14 @@ namespace AZ * { * 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::GetInstance) + * behaviorContext->ConstantProperty("g_MySystem", MySystemProxy::GetProxy) * ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) * ->Attribute(AZ::Script::Attributes::Module, "MyModule"); * @@ -60,26 +61,6 @@ namespace AZ AZ_CLASS_ALLOCATOR(BehaviorInterfaceProxy, AZ::SystemAllocator, 0); AZ_RTTI(BehaviorInterfaceProxy, "{E7CC8D27-4499-454E-A7DF-3F72FBECD30D}"); - //! Accessor for use with ConstantProperty - 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; - } - - //! Helper for attaching interface function via ClassBuilder::Method - template - static auto WrapMethod() - { - using FuncTraits = AZStd::function_traits>; - return FuncTraits::template expand_args::template WrapMethod(); - } - BehaviorInterfaceProxy() = default; virtual ~BehaviorInterfaceProxy() = default; @@ -98,25 +79,48 @@ namespace AZ //! Returns if the m_instance shared pointer is non-nullptr bool IsValid() const { return m_instance; } - private: - template + 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 + template static auto WrapMethod() { - using return_type = AZStd::function_traits_get_result_t>; - return [](BehaviorInterfaceProxy* proxy, Args... params) -> return_type + 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 return_type(); + 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 From ecae08fa955c7852c87a52f24c46bac215b5b2ea Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 28 Oct 2021 12:05:56 -0700 Subject: [PATCH 092/200] Made some improvements for debugging shader hot reload issues. Made ShaderReloadDebugTracker store its static data in Environment system variables, so they are shared across dlls. This fixes issues with inconsistent indenting when debug operations are performed in different libraries. New ShaderReloadDebugTracker operations in FullscreenTrianglePass. Added a ShaderReloadDebugTracker message to Shader::GetVariant that includes asset built timestamp infromation, which I think will be really helpful in sorting out reload issues. Renamed some functions and variables to remove a redundant "ShaderAsset" term. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Include/Atom/RPI.Public/Shader/Shader.h | 2 + .../Shader/ShaderReloadDebugTracker.h | 20 ++++--- .../Atom/RPI.Reflect/Shader/ShaderAsset.h | 4 +- .../Pass/FullscreenTrianglePass.cpp | 6 ++ .../Code/Source/RPI.Public/Shader/Shader.cpp | 28 ++++++++- .../Shader/ShaderReloadDebugTracker.cpp | 57 ++++++++++++++++++- .../Source/RPI.Public/Shader/ShaderSystem.cpp | 4 ++ .../Source/RPI.Reflect/Shader/ShaderAsset.cpp | 10 ++-- .../RPI.Reflect/Shader/ShaderAssetCreator.cpp | 4 +- 9 files changed, 114 insertions(+), 21 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h index e2568f3b61..bae9c4d8cc 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/Shader.h @@ -154,6 +154,8 @@ namespace AZ ConstPtr LoadPipelineLibrary() const; void SavePipelineLibrary() const; + + const ShaderVariant& GetVariantInternal(ShaderVariantStableId shaderVariantStableId); /////////////////////////////////////////////////////////////////// /// AssetBus overrides diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h index 27c43afd12..dcbc4a5774 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderReloadDebugTracker.h @@ -24,6 +24,9 @@ namespace AZ class ShaderReloadDebugTracker final { public: + static void Init(); + static void Shutdown(); + static bool IsEnabled(); //! Begin a code section. Will print a "[BEGIN] " header, and all subsequent calls will be indented. @@ -34,8 +37,8 @@ namespace AZ if (IsEnabled()) { const AZStd::string sectionName = AZStd::string::format(sectionNameFormat, args...); - AZ_TracePrintf("ShaderReloadDebug", "%*s [BEGIN] %s \n", s_indent, "", sectionName.c_str()); - s_indent += IndentSpaces; + AZ_TracePrintf("ShaderReloadDebug", "%*s [BEGIN] %s \n", GetIndent(), "", sectionName.c_str()); + AddIndent(); } #endif } @@ -48,8 +51,8 @@ namespace AZ if (IsEnabled()) { const AZStd::string sectionName = AZStd::string::format(sectionNameFormat, args...); - s_indent -= IndentSpaces; - AZ_TracePrintf("ShaderReloadDebug", "%*s [_END_] %s \n", s_indent, "", sectionName.c_str()); + RemoveIndent(); + AZ_TracePrintf("ShaderReloadDebug", "%*s [_END_] %s \n", GetIndent(), "", sectionName.c_str()); } #endif } @@ -63,7 +66,7 @@ namespace AZ { const AZStd::string message = AZStd::string::format(format, args...); - AZ_TracePrintf("ShaderReloadDebug", "%*s %s \n", s_indent, "", message.c_str()); + AZ_TracePrintf("ShaderReloadDebug", "%*s %s \n", GetIndent(), "", message.c_str()); } #endif } @@ -86,9 +89,12 @@ namespace AZ }; private: - static bool s_enabled; - static int s_indent; static constexpr int IndentSpaces = 4; + + static void MakeReady(); + static void AddIndent(); + static void RemoveIndent(); + static int GetIndent(); }; } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h index 2c24d6052a..5da990eedb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h @@ -96,7 +96,7 @@ namespace AZ //! Return the timestamp when the shader asset was built. //! This is used to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload. - AZStd::sys_time_t GetShaderAssetBuildTimestamp() const; + AZStd::sys_time_t GetBuildTimestamp() const; //! Returns the shader option group layout. const ShaderOptionGroupLayout* GetShaderOptionGroupLayout() const; @@ -297,7 +297,7 @@ namespace AZ Name m_drawListName; //! Use to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload. - AZStd::sys_time_t m_shaderAssetBuildTimestamp = 0; + AZStd::sys_time_t m_buildTimestamp = 0; /////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp index 40dce7d138..0bd32344d6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/FullscreenTrianglePass.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -46,16 +47,19 @@ namespace AZ void FullscreenTrianglePass::OnShaderReinitialized(const Shader&) { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::OnShaderReinitialized", this); LoadShader(); } void FullscreenTrianglePass::OnShaderAssetReinitialized(const Data::Asset&) { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::OnShaderAssetReinitialized", this); LoadShader(); } void FullscreenTrianglePass::OnShaderVariantReinitialized(const ShaderVariant&) { + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::OnShaderVariantReinitialized", this); LoadShader(); } @@ -129,6 +133,8 @@ namespace AZ void FullscreenTrianglePass::InitializeInternal() { RenderPass::InitializeInternal(); + + ShaderReloadDebugTracker::ScopedSection reloadSection("{%p}->FullscreenTrianglePass::InitializeInternal", this); // This draw item purposefully does not reference any geometry buffers. // Instead it's expected that the extended class uses a vertex shader diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp index 51dd9c36d3..bee9200c07 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp @@ -320,6 +320,30 @@ namespace AZ } const ShaderVariant& Shader::GetVariant(ShaderVariantStableId shaderVariantStableId) + { + const ShaderVariant& variant = GetVariantInternal(shaderVariantStableId); + + if (ShaderReloadDebugTracker::IsEnabled()) + { + auto makeTimeString = [](AZStd::sys_time_t timestamp, AZStd::sys_time_t now) + { + AZStd::sys_time_t elapsedMicroseconds = now - timestamp; + double elapsedSeconds = aznumeric_cast(elapsedMicroseconds / 1'000'000); + AZStd::string timeString = AZStd::string::format("%lld (%f seconds ago)", timestamp, elapsedSeconds); + return timeString; + }; + + AZStd::sys_time_t now = AZStd::GetTimeNowMicroSecond(); + + ShaderReloadDebugTracker::Printf("{%p}->Shader::GetVariant for shader '%s' [build time %s] found variant '%s' [build time %s]", this, + m_asset.GetHint().c_str(), makeTimeString(m_asset->GetBuildTimestamp(), now).c_str(), + variant.GetShaderVariantAsset().GetHint().c_str(), makeTimeString(variant.GetShaderVariantAsset()->GetBuildTimestamp(), now).c_str()); + } + + return variant; + } + + const ShaderVariant& Shader::GetVariantInternal(ShaderVariantStableId shaderVariantStableId) { if (!shaderVariantStableId.IsValid() || shaderVariantStableId == ShaderAsset::RootShaderVariantStableId) { @@ -336,7 +360,7 @@ namespace AZ // reloaded, but some (or all) shader variants haven't been built yet. Since we want to use the latest version of the // shader code, ignore the old variants and fall back to the newer root variant instead. There's no need to report a // warning here because m_asset->GetVariant below will report one. - if (findIt->second.GetBuildTimestamp() >= m_asset->GetShaderAssetBuildTimestamp()) + if (findIt->second.GetBuildTimestamp() >= m_asset->GetBuildTimestamp()) { return findIt->second; } @@ -359,7 +383,7 @@ namespace AZ auto findIt = m_shaderVariants.find(shaderVariantStableId); if (findIt != m_shaderVariants.end()) { - if (findIt->second.GetBuildTimestamp() >= m_asset->GetShaderAssetBuildTimestamp()) + if (findIt->second.GetBuildTimestamp() >= m_asset->GetBuildTimestamp()) { return findIt->second; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderReloadDebugTracker.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderReloadDebugTracker.cpp index 6b97e43cbd..3e7ff826cf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderReloadDebugTracker.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderReloadDebugTracker.cpp @@ -7,24 +7,75 @@ */ #include +#include namespace AZ { namespace RPI { - bool ShaderReloadDebugTracker::s_enabled = false; - int ShaderReloadDebugTracker::s_indent = 0; + namespace ShaderReloadDebugTrackerInternal + { + static const char EnabledVariableName[] = "ShaderReloadDebugTracker enabled"; + static const char IndentVariableName[] = "ShaderReloadDebugTracker indent"; + + static EnvironmentVariable s_enabled; + static EnvironmentVariable s_indent; + } + + void ShaderReloadDebugTracker::Init() + { + ShaderReloadDebugTrackerInternal::s_enabled = AZ::Environment::CreateVariable(ShaderReloadDebugTrackerInternal::EnabledVariableName); + ShaderReloadDebugTrackerInternal::s_indent = AZ::Environment::CreateVariable(ShaderReloadDebugTrackerInternal::IndentVariableName); + + ShaderReloadDebugTrackerInternal::s_enabled.Get() = false; + ShaderReloadDebugTrackerInternal::s_indent.Get() = 0; + } + + void ShaderReloadDebugTracker::Shutdown() + { + ShaderReloadDebugTrackerInternal::s_enabled.Reset(); + ShaderReloadDebugTrackerInternal::s_indent.Reset(); + } + + void ShaderReloadDebugTracker::MakeReady() + { + if (!ShaderReloadDebugTrackerInternal::s_enabled.IsValid()) + { + ShaderReloadDebugTrackerInternal::s_enabled = AZ::Environment::FindVariable(ShaderReloadDebugTrackerInternal::EnabledVariableName); + ShaderReloadDebugTrackerInternal::s_indent = AZ::Environment::FindVariable(ShaderReloadDebugTrackerInternal::IndentVariableName); + } + } bool ShaderReloadDebugTracker::IsEnabled() { #ifdef AZ_ENABLE_SHADER_RELOAD_DEBUG_TRACKER + MakeReady(); + // Set this to true in the debugger to turn on hot reload tracing. // If needed, we could hook this up to a CVar. - return s_enabled; + return ShaderReloadDebugTrackerInternal::s_enabled.Get(); #else return false; #endif } + + void ShaderReloadDebugTracker::AddIndent() + { + MakeReady(); + ShaderReloadDebugTrackerInternal::s_indent.Get() += IndentSpaces; + } + + void ShaderReloadDebugTracker::RemoveIndent() + { + MakeReady(); + ShaderReloadDebugTrackerInternal::s_indent.Get() -= IndentSpaces; + } + + int ShaderReloadDebugTracker::GetIndent() + { + MakeReady(); + return ShaderReloadDebugTrackerInternal::s_indent.Get(); + } ShaderReloadDebugTracker::ScopedSection::~ScopedSection() { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderSystem.cpp index ec6aeb3771..2e66aaca99 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderSystem.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -86,10 +87,13 @@ namespace AZ }; Data::InstanceDatabase::Create(azrtti_typeid(), handler, false); } + + ShaderReloadDebugTracker::Init(); } void ShaderSystem::Shutdown() { + ShaderReloadDebugTracker::Shutdown(); Data::InstanceDatabase::Destroy(); Data::InstanceDatabase::Destroy(); Data::InstanceDatabase::Destroy(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp index 84757d58ab..9fa76ac5ee 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAsset.cpp @@ -100,7 +100,7 @@ namespace AZ ->Field("pipelineStateType", &ShaderAsset::m_pipelineStateType) ->Field("shaderOptionGroupLayout", &ShaderAsset::m_shaderOptionGroupLayout) ->Field("drawListName", &ShaderAsset::m_drawListName) - ->Field("shaderAssetBuildTimestamp", &ShaderAsset::m_shaderAssetBuildTimestamp) + ->Field("shaderAssetBuildTimestamp", &ShaderAsset::m_buildTimestamp) ->Field("perAPIShaderData", &ShaderAsset::m_perAPIShaderData) ; } @@ -134,11 +134,11 @@ namespace AZ return m_drawListName; } - AZStd::sys_time_t ShaderAsset::GetShaderAssetBuildTimestamp() const + AZStd::sys_time_t ShaderAsset::GetBuildTimestamp() const { - return m_shaderAssetBuildTimestamp; + return m_buildTimestamp; } - + void ShaderAsset::SetReady() { m_status = AssetStatus::Ready; @@ -256,7 +256,7 @@ namespace AZ } return GetRootVariant(supervariantIndex); } - else if (variant->GetBuildTimestamp() >= m_shaderAssetBuildTimestamp) + else if (variant->GetBuildTimestamp() >= m_buildTimestamp) { return variant; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAssetCreator.cpp index 87338f2185..5df37aa211 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderAssetCreator.cpp @@ -21,7 +21,7 @@ namespace AZ { if (ValidateIsReady()) { - m_asset->m_shaderAssetBuildTimestamp = shaderAssetBuildTimestamp; + m_asset->m_buildTimestamp = shaderAssetBuildTimestamp; } } @@ -390,7 +390,7 @@ namespace AZ m_asset->m_pipelineStateType = sourceShaderAsset.m_pipelineStateType; m_asset->m_drawListName = sourceShaderAsset.m_drawListName; m_asset->m_shaderOptionGroupLayout = sourceShaderAsset.m_shaderOptionGroupLayout; - m_asset->m_shaderAssetBuildTimestamp = sourceShaderAsset.m_shaderAssetBuildTimestamp; + m_asset->m_buildTimestamp = sourceShaderAsset.m_buildTimestamp; // copy root variant assets for (auto& perAPIShaderData : sourceShaderAsset.m_perAPIShaderData) From e56396a817c295ddf19e25ba612e617943d6d87a Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Thu, 28 Oct 2021 14:30:14 -0500 Subject: [PATCH 093/200] Improvements to C++/Python tool gemplates Signed-off-by: Chris Galvan --- Code/Editor/Core/LevelEditorMenuHandler.cpp | 2 +- .../AzToolsFramework/API/ViewPaneOptions.h | 2 +- .../Application/ToolsApplication.cpp | 2 + .../Editor/Scripts/az_qt_helpers.py | 8 +- .../Source/${Name}EditorSystemComponent.cpp | 4 +- .../Template/Code/Source/${Name}Widget.cpp | 2 - .../Code/${NameLower}_editor_files.cmake | 1 + .../Template/Code/CMakeLists.txt | 1 + .../Template/Code/Source/${Name}.qrc | 5 + .../Code/Source/${Name}EditorModule.cpp | 8 ++ .../Template/Code/Source/toolbar_icon.svg | 1 + .../Editor/Scripts/${NameLower}_dialog.py | 17 +-- .../Template/Editor/Scripts/bootstrap.py | 113 ++---------------- Templates/PythonToolGem/template.json | 12 ++ 14 files changed, 50 insertions(+), 128 deletions(-) create mode 100644 Templates/PythonToolGem/Template/Code/Source/${Name}.qrc create mode 100644 Templates/PythonToolGem/Template/Code/Source/toolbar_icon.svg 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/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 cdafa63eba..3c7495e836 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -424,6 +424,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/Gems/QtForPython/Editor/Scripts/az_qt_helpers.py b/Gems/QtForPython/Editor/Scripts/az_qt_helpers.py index 758cc539d7..96f55f14b0 100755 --- a/Gems/QtForPython/Editor/Scripts/az_qt_helpers.py +++ b/Gems/QtForPython/Editor/Scripts/az_qt_helpers.py @@ -27,7 +27,7 @@ def get_editor_main_window(): return editor_main_window # Helper method for registering a Python widget as a tool/view pane with the Editor -def register_view_pane(name, widget_type, options=editor.ViewPaneOptions()): +def register_view_pane(name, widget_type, category="Tools", options=editor.ViewPaneOptions()): global view_pane_handlers # The view pane names are unique in the Editor, so make sure one with the same name doesn't exist already @@ -45,10 +45,10 @@ def register_view_pane(name, widget_type, options=editor.ViewPaneOptions()): return new_widget.winId() - def on_notify_register_views(parameters, my_name=name, my_options=options): + def on_notify_register_views(parameters, my_name=name, my_category=category, my_options=options): # Register our widget as an Editor view pane print('Calling on_notify_register_views RegisterCustomViewPane') - editor.EditorRequestBus(azlmbr.bus.Broadcast, 'RegisterCustomViewPane', my_name, 'Tools', my_options) + editor.EditorRequestBus(azlmbr.bus.Broadcast, 'RegisterCustomViewPane', my_name, my_category, my_options) # We keep a handler around in case a request for registering custom view panes comes later print('Initializing callback for RegisterCustomViewPane') @@ -57,7 +57,7 @@ def register_view_pane(name, widget_type, options=editor.ViewPaneOptions()): registration_handler.add_callback("NotifyRegisterViews", on_notify_register_views) global registration_handlers registration_handlers[name] = registration_handler - editor.EditorRequestBus(azlmbr.bus.Broadcast, 'RegisterCustomViewPane', name, 'Tools', options) + editor.EditorRequestBus(azlmbr.bus.Broadcast, 'RegisterCustomViewPane', name, category, options) # Connect to the ViewPaneCallbackBus in order to respond to requests to create our widget # We also need to store our handler so it will exist for the life of the Editor diff --git a/Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp index f12fa04929..4206340c57 100644 --- a/Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp +++ b/Templates/CppToolGem/Template/Code/Source/${Name}EditorSystemComponent.cpp @@ -71,8 +71,8 @@ namespace ${SanitizedCppName} options.showOnToolsToolbar = true; options.toolbarIcon = ":/${Name}/toolbar_icon.svg"; - // Register our custom widget as a dockable tool with the Editor - AzToolsFramework::RegisterViewPane<${SanitizedCppName}Widget>("${Name}", "Tools", options); + // Register our custom widget as a dockable tool with the Editor under an Examples sub-menu + AzToolsFramework::RegisterViewPane<${SanitizedCppName}Widget>("${Name}", "Examples", options); } } // namespace ${SanitizedCppName} diff --git a/Templates/CppToolGem/Template/Code/Source/${Name}Widget.cpp b/Templates/CppToolGem/Template/Code/Source/${Name}Widget.cpp index bd6dd6c86a..a5128fb192 100644 --- a/Templates/CppToolGem/Template/Code/Source/${Name}Widget.cpp +++ b/Templates/CppToolGem/Template/Code/Source/${Name}Widget.cpp @@ -20,8 +20,6 @@ namespace ${SanitizedCppName} ${SanitizedCppName}Widget::${SanitizedCppName}Widget(QWidget* parent) : QWidget(parent) { - setWindowTitle(QObject::tr("${Name}")); - QVBoxLayout* mainLayout = new QVBoxLayout(this); QLabel* introLabel = new QLabel(QObject::tr("Put your cool stuff here!"), this); diff --git a/Templates/PythonToolGem/Template/Code/${NameLower}_editor_files.cmake b/Templates/PythonToolGem/Template/Code/${NameLower}_editor_files.cmake index 8362d37f52..88aaea843f 100644 --- a/Templates/PythonToolGem/Template/Code/${NameLower}_editor_files.cmake +++ b/Templates/PythonToolGem/Template/Code/${NameLower}_editor_files.cmake @@ -11,4 +11,5 @@ set(FILES Source/${Name}ModuleInterface.h Source/${Name}EditorSystemComponent.cpp Source/${Name}EditorSystemComponent.h + Source/${Name}.qrc ) diff --git a/Templates/PythonToolGem/Template/Code/CMakeLists.txt b/Templates/PythonToolGem/Template/Code/CMakeLists.txt index b7a5ac89a9..a6044e717b 100644 --- a/Templates/PythonToolGem/Template/Code/CMakeLists.txt +++ b/Templates/PythonToolGem/Template/Code/CMakeLists.txt @@ -26,6 +26,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( NAME ${Name}.Editor.Static STATIC NAMESPACE Gem + AUTORCC FILES_CMAKE ${NameLower}_editor_files.cmake INCLUDE_DIRECTORIES diff --git a/Templates/PythonToolGem/Template/Code/Source/${Name}.qrc b/Templates/PythonToolGem/Template/Code/Source/${Name}.qrc new file mode 100644 index 0000000000..90d7695b88 --- /dev/null +++ b/Templates/PythonToolGem/Template/Code/Source/${Name}.qrc @@ -0,0 +1,5 @@ + + + toolbar_icon.svg + + diff --git a/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp index 644c513747..0027af011a 100644 --- a/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp +++ b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp @@ -11,6 +11,12 @@ #include <${Name}ModuleInterface.h> #include <${Name}EditorSystemComponent.h> +void Init${SanitizedCppName}Resources() +{ + // We must register our Qt resources (.qrc file) since this is being loaded from a separate module (gem) + Q_INIT_RESOURCE(${SanitizedCppName}); +} + namespace ${SanitizedCppName} { class ${SanitizedCppName}EditorModule @@ -22,6 +28,8 @@ namespace ${SanitizedCppName} ${SanitizedCppName}EditorModule() { + Init${SanitizedCppName}Resources(); + // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. // Add ALL components descriptors associated with this gem to m_descriptors. // This will associate the AzTypeInfo information for the components with the the SerializeContext, BehaviorContext and EditContext. diff --git a/Templates/PythonToolGem/Template/Code/Source/toolbar_icon.svg b/Templates/PythonToolGem/Template/Code/Source/toolbar_icon.svg new file mode 100644 index 0000000000..59de66961c --- /dev/null +++ b/Templates/PythonToolGem/Template/Code/Source/toolbar_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Templates/PythonToolGem/Template/Editor/Scripts/${NameLower}_dialog.py b/Templates/PythonToolGem/Template/Editor/Scripts/${NameLower}_dialog.py index 39515711ae..19194ec97f 100644 --- a/Templates/PythonToolGem/Template/Editor/Scripts/${NameLower}_dialog.py +++ b/Templates/PythonToolGem/Template/Editor/Scripts/${NameLower}_dialog.py @@ -6,24 +6,15 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ # ------------------------------------------------------------------------- """${SanitizedCppName}\\editor\\scripts\\${SanitizedCppName}_dialog.py -Generated from O3DE PythonGem Template""" +Generated from O3DE PythonToolGem Template""" -import azlmbr -from shiboken2 import wrapInstance, getCppPointer -from PySide2 import QtCore, QtWidgets, QtGui -from PySide2.QtCore import QEvent, Qt -from PySide2.QtWidgets import QVBoxLayout, QAction, QDialog, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTreeWidget, QTreeWidgetItem, QWidget, QAbstractButton - -# Once PySide2 has been bootstrapped, register our ${SanitizedCppName}Dialog with the Editor +from PySide2.QtCore import Qt +from PySide2.QtWidgets import QDialog, QLabel, QVBoxLayout class ${SanitizedCppName}Dialog(QDialog): def __init__(self, parent=None): super(${SanitizedCppName}Dialog, self).__init__(parent) - self.setObjectName("${SanitizedCppName}Dialog") - - self.setWindowTitle("HelloWorld, ${SanitizedCppName} Dialog") - self.mainLayout = QVBoxLayout(self) self.introLabel = QLabel("Put your cool stuff here!") @@ -42,5 +33,3 @@ class ${SanitizedCppName}Dialog(QDialog): self.mainLayout.addWidget(self.helpLabel, 0, Qt.AlignCenter) self.setLayout(self.mainLayout) - - return \ No newline at end of file diff --git a/Templates/PythonToolGem/Template/Editor/Scripts/bootstrap.py b/Templates/PythonToolGem/Template/Editor/Scripts/bootstrap.py index 060116d36c..d49babfa96 100644 --- a/Templates/PythonToolGem/Template/Editor/Scripts/bootstrap.py +++ b/Templates/PythonToolGem/Template/Editor/Scripts/bootstrap.py @@ -6,112 +6,17 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ # ------------------------------------------------------------------------- """${SanitizedCppName}\\editor\\scripts\\boostrap.py -Generated from O3DE PythonGem Template""" +Generated from O3DE PythonToolGem Template""" -import azlmbr import az_qt_helpers -from PySide2 import QtCore, QtWidgets, QtGui -from PySide2.QtCore import QEvent, Qt -from PySide2.QtWidgets import QMainWindow, QAction, QDialog, QHeaderView, QLabel, QLineEdit, QPushButton, QSplitter, QTreeWidget, QTreeWidgetItem, QWidget, QAbstractButton -# ------------------------------------------------------------------------- - - -# ------------------------------------------------------------------------- -class SampleUI(QtWidgets.QDialog): - """Lightweight UI Test Class created a button""" - def __init__(self, parent, title='Not Set'): - super(SampleUI, self).__init__(parent) - self.setWindowTitle(title) - self.initUI() - - def initUI(self): - mainLayout = QtWidgets.QHBoxLayout() - testBtn = QtWidgets.QPushButton("I am just a Button man!") - mainLayout.addWidget(testBtn) - self.setLayout(mainLayout) -# ------------------------------------------------------------------------- +import azlmbr.editor as editor +from ${NameLower}_dialog import ${SanitizedCppName}Dialog if __name__ == "__main__": - print("${SanitizedCppName}.boostrap, Generated from O3DE PythonGem Template") - - # --------------------------------------------------------------------- - # validate pyside before continuing - try: - azlmbr.qt.QtForPythonRequestBus(azlmbr.bus.Broadcast, 'IsActive') - params = azlmbr.qt.QtForPythonRequestBus(azlmbr.bus.Broadcast, 'GetQtBootstrapParameters') - params is not None and params.mainWindowId is not 0 - from PySide2 import QtWidgets - except Exception as e: - _LOGGER.error(f'Pyside not available, exception: {e}') - raise e - - # keep going, import the other PySide2 bits we will use - from PySide2 import QtGui - from PySide2.QtCore import Slot - from shiboken2 import wrapInstance, getCppPointer - - # Get our Editor main window - _widget_main_window = None - try: - _widget_main_window = az_qt_helpers.get_editor_main_window() - except: - pass # may be booting in the AP? - # --------------------------------------------------------------------- - - - # --------------------------------------------------------------------- - if _widget_main_window: - # creat a custom menu - _tag_str = '${SanitizedCppName}' - - # create our own menuBar - ${SanitizedCppName}_menu = _widget_main_window.menuBar().addMenu(f"&{_tag_str}") - - # nest a menu for util/tool launching - ${SanitizedCppName}_launch_menu = ${SanitizedCppName}_menu.addMenu("examples") - else: - print('No O3DE MainWindow') - # --------------------------------------------------------------------- - - - # --------------------------------------------------------------------- - if _widget_main_window: - # (1) add the first SampleUI - action_launch_sample_ui = ${SanitizedCppName}_launch_menu.addAction("O3DE:SampleUI") - - @Slot() - def clicked_sample_ui(): - while 1: # simple PySide2 test, set to 0 to disable - ui = SampleUI(parent=_widget_main_window, title='O3DE:SampleUI') - ui.show() - break - return - # Add click event to menu bar - action_launch_sample_ui.triggered.connect(clicked_sample_ui) - # --------------------------------------------------------------------- - - - # --------------------------------------------------------------------- - if _widget_main_window: - # (1) and custom external module Qwidget - action_launch_${SanitizedCppName}_dialog = ${SanitizedCppName}_launch_menu.addAction("O3DE:${SanitizedCppName}_dialog") - - @Slot() - def clicked_${SanitizedCppName}_dialog(): - while 1: # simple PySide2 test, set to 0 to disable - try: - import az_qt_helpers - from ${NameLower}_dialog import ${SanitizedCppName}Dialog - az_qt_helpers.register_view_pane('${SanitizedCppName} Popup', ${SanitizedCppName}Dialog) - except Exception as e: - print(f'Error: {e}') - print('Skipping register our ${SanitizedCppName}Dialog with the Editor.') - ${SanitizedCppName}_dialog = ${SanitizedCppName}Dialog(parent=_widget_main_window) - ${SanitizedCppName}_dialog.show() - break - return - # Add click event to menu bar - action_launch_${SanitizedCppName}_dialog.triggered.connect(clicked_${SanitizedCppName}_dialog) - # --------------------------------------------------------------------- + print("${SanitizedCppName}.boostrap, Generated from O3DE PythonToolGem Template") - # end \ No newline at end of file + # Register our custom widget as a dockable tool with the Editor under an Examples sub-menu + options = editor.ViewPaneOptions() + options.showOnToolsToolbar = True + options.toolbarIcon = ":/${Name}/toolbar_icon.svg" + az_qt_helpers.register_view_pane('${SanitizedCppName}', ${SanitizedCppName}Dialog, category="Examples", options=options) diff --git a/Templates/PythonToolGem/template.json b/Templates/PythonToolGem/template.json index 4d85373ead..9f4aded036 100644 --- a/Templates/PythonToolGem/template.json +++ b/Templates/PythonToolGem/template.json @@ -102,6 +102,12 @@ "isTemplated": true, "isOptional": false }, + { + "file": "Code/Source/${Name}.qrc", + "origin": "Code/Source/${Name}.qrc", + "isTemplated": true, + "isOptional": false + }, { "file": "Code/Source/${Name}EditorModule.cpp", "origin": "Code/Source/${Name}EditorModule.cpp", @@ -126,6 +132,12 @@ "isTemplated": true, "isOptional": false }, + { + "file": "Code/Source/toolbar_icon.svg", + "origin": "Code/Source/toolbar_icon.svg", + "isTemplated": false, + "isOptional": false + }, { "file": "Code/Tests/${Name}EditorTest.cpp", "origin": "Code/Tests/${Name}EditorTest.cpp", From 90509c7fa20068f7dbe271aa08b8864a59ff3aa5 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 28 Oct 2021 14:18:04 -0700 Subject: [PATCH 094/200] [profiler_capture_api] removed now unnecessary ProfilerRequests EBus alias after AZ::Interface conversion Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h | 13 ------------- .../Code/Source/ProfilerSystemComponent.cpp | 4 ---- Gems/Profiler/Code/Source/ProfilerSystemComponent.h | 4 ++-- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h index 9194381e23..322bfb60c2 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h @@ -60,20 +60,7 @@ namespace AZ virtual bool EndCapture() = 0; }; - class ProfilerRequestsTraits - : public AZ::EBusTraits - { - public: - // EBusTraits overrides - static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - - // Allow multiple threads to concurrently make requests - using MutexType = AZStd::mutex; - }; - using ProfilerSystemInterface = AZ::Interface; - using ProfilerRequestBus = AZ::EBus; //! 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 diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp index 4deda64964..24da9e050e 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp @@ -144,8 +144,6 @@ namespace Profiler void ProfilerSystemComponent::Activate() { - AZ::Debug::ProfilerRequestBus::Handler::BusConnect(); - m_cpuProfiler.Init(); } @@ -153,8 +151,6 @@ namespace Profiler { m_cpuProfiler.Shutdown(); - AZ::Debug::ProfilerRequestBus::Handler::BusDisconnect(); - // Block deactivation until the IO thread has finished serializing the CPU data if (m_cpuDataSerializationThread.joinable()) { diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h index 000b11cfdf..a1c8c47479 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h @@ -18,7 +18,7 @@ namespace Profiler { class ProfilerSystemComponent : public AZ::Component - , protected AZ::Debug::ProfilerRequestBus::Handler + , protected AZ::Debug::ProfilerRequests { public: AZ_COMPONENT(ProfilerSystemComponent, "{3f52c1d7-d920-4781-8ed7-88077ec4f305}"); @@ -38,7 +38,7 @@ namespace Profiler void Activate() override; void Deactivate() override; - // ProfilerRequestBus interface implementation + // ProfilerRequests interface implementation bool IsActive() const override; void SetActive(bool active) override; bool CaptureFrame(const AZStd::string& outputFilePath) override; From e67db19a630d08b6302528a943f0033a6c1c32fe Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 28 Oct 2021 14:26:22 -0700 Subject: [PATCH 095/200] [profiler_capture_api] add sample python script to test Profiler System interface bindings Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- .../Editor/Scripts/Profiler/__init__.py | 7 +++++ .../Profiler/profiler_system_example.py | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 AutomatedTesting/Editor/Scripts/Profiler/__init__.py create mode 100644 AutomatedTesting/Editor/Scripts/Profiler/profiler_system_example.py diff --git a/AutomatedTesting/Editor/Scripts/Profiler/__init__.py b/AutomatedTesting/Editor/Scripts/Profiler/__init__.py new file mode 100644 index 0000000000..a26f3b57be --- /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 +# +# \ No newline at end of file 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() From 9bc0422f0b0fcf6a23361642f8b0a8166f4fad5c Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 28 Oct 2021 14:39:17 -0700 Subject: [PATCH 096/200] [profiler_capture_api] added trailing newlines to a couple new files Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- AutomatedTesting/Editor/Scripts/Profiler/__init__.py | 2 +- Registry/profiler.setreg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Editor/Scripts/Profiler/__init__.py b/AutomatedTesting/Editor/Scripts/Profiler/__init__.py index a26f3b57be..7a325ca97e 100644 --- a/AutomatedTesting/Editor/Scripts/Profiler/__init__.py +++ b/AutomatedTesting/Editor/Scripts/Profiler/__init__.py @@ -4,4 +4,4 @@ # # SPDX-License-Identifier: Apache-2.0 OR MIT # -# \ No newline at end of file +# diff --git a/Registry/profiler.setreg b/Registry/profiler.setreg index a295b007e1..b46bfd8beb 100644 --- a/Registry/profiler.setreg +++ b/Registry/profiler.setreg @@ -12,4 +12,4 @@ } } } -} \ No newline at end of file +} From 9dac7270928d67e1afdba0fe842df0358fb27563 Mon Sep 17 00:00:00 2001 From: hershey5045 <43485729+hershey5045@users.noreply.github.com> Date: Thu, 28 Oct 2021 15:21:47 -0700 Subject: [PATCH 097/200] Add component activation in LUT activation script. (#5101) Signed-off-by: rbarrand Co-authored-by: rbarrand --- .../Common/Editor/Scripts/ColorGrading/activate_lut_asset.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py index 016ad024aa..8fe3126a77 100644 --- a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/activate_lut_asset.py @@ -60,6 +60,11 @@ def activate_look_modification_lut(look_modification_component, asset_relative_p LOOK_MODIFICATION_ENABLE_PROPERTY_PATH, True ) + azlmbr.editor.EditorComponentAPIBus( + azlmbr.bus.Broadcast, + "EnableComponents", + [look_modification_component] + ) def activate_lut_asset(entity_id, asset_relative_path): disable_hdr_color_grading_component(entity_id) From 5971f1176e2da893c06c90aa77ac712254b421c3 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 28 Oct 2021 16:17:28 -0700 Subject: [PATCH 098/200] Fix thrown exceptions if repos does not exist in the manifest Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/register.py | 6 +++--- scripts/o3de/o3de/repo.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index 6ad54a11f3..8a2bb788aa 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -477,11 +477,11 @@ def register_repo(json_data: dict, parsed_uri = urllib.parse.urlparse(url) if parsed_uri.scheme in ['http', 'https', 'ftp', 'ftps']: - while repo_uri in json_data['repos']: + while repo_uri in json_data.get('repos', []): json_data['repos'].remove(repo_uri) else: repo_uri = pathlib.Path(repo_uri).resolve().as_posix() - while repo_uri in json_data['repos']: + while repo_uri in json_data.get('repos', []): json_data['repos'].remove(repo_uri) if remove: @@ -492,7 +492,7 @@ def register_repo(json_data: dict, result = utils.download_file(parsed_uri, cache_file) if result == 0: - json_data['repos'].insert(0, repo_uri) + json_data.setdefault('repos', []).insert(0, repo_uri) repo_set = set() result = repo.process_add_o3de_repo(cache_file, repo_set) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index 32c2cba428..db20fe8ce9 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -147,7 +147,7 @@ def get_gem_json_paths_from_all_cached_repos() -> set: json_data = manifest.load_o3de_manifest() gem_set = set() - for repo_uri in json_data['repos']: + for repo_uri in json_data.get('repos', []): gem_set.update(get_gem_json_paths_from_cached_repo(repo_uri)) return gem_set From d355942e8b6ee8295973a2a522311693c9f86e76 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Thu, 28 Oct 2021 16:36:54 -0700 Subject: [PATCH 099/200] Fix an additional location Signed-off-by: AMZN-Phil --- scripts/o3de/o3de/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index db20fe8ce9..a6b1505761 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -189,7 +189,7 @@ def refresh_repos() -> int: # set will stop circular references repo_set = set() - for repo_uri in json_data['repos']: + for repo_uri in json_data.get('repos', []): if repo_uri not in repo_set: repo_set.add(repo_uri) From 021917ad274bc805417bbe6f9e221817c6daede7 Mon Sep 17 00:00:00 2001 From: John Jones-Steele <82226755+jjjoness@users.noreply.github.com> Date: Fri, 29 Oct 2021 09:42:40 +0100 Subject: [PATCH 100/200] Fix bug 4198 (#5107) Signed-off-by: John Jones-Steele --- .../Code/Source/Components/TerrainWorldComponent.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp index d8b7308ef7..bd65cf6abc 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainWorldComponent.cpp @@ -32,16 +32,22 @@ namespace Terrain AZ::EditContext* edit = serialize->GetEditContext(); if (edit) { - edit->Class( - "Terrain World Component", "Data required for the terrain system to run") + edit->Class("Terrain World Component", "Data required for the terrain system to run") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector({ AZ_CRC_CE("Level") })) ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMin, "World Bounds (Min)", "") + // Temporary constraint until the rest of the Terrain system is updated to support larger worlds. + ->Attribute(AZ::Edit::Attributes::Min, -2048.0f) + ->Attribute(AZ::Edit::Attributes::Max, 2048.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMax, "World Bounds (Max)", "") - ->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "") + // Temporary constraint until the rest of the Terrain system is updated to support larger worlds. + ->Attribute(AZ::Edit::Attributes::Min, -2048.0f) + ->Attribute(AZ::Edit::Attributes::Max, 2048.0f) + ->DataElement( + AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "") ; } } From b4dd4c8f02842b99049bfef46985234d92d34a0e Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 29 Oct 2021 09:20:52 -0700 Subject: [PATCH 101/200] Add engine name, folder and fix refresh crash (#5112) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Resources/ProjectManager.qss | 10 ++++-- .../Source/EngineSettingsScreen.cpp | 32 ++++++++++++++++--- .../Source/EngineSettingsScreen.h | 1 - .../Source/FormBrowseEditWidget.cpp | 5 +-- .../Source/FormBrowseEditWidget.h | 5 ++- .../Source/GemCatalog/GemCatalogScreen.cpp | 2 +- .../Source/GemCatalog/GemModel.cpp | 1 + .../Source/UpdateProjectSettingsScreen.cpp | 1 + 8 files changed, 44 insertions(+), 13 deletions(-) diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index e755964a7f..d3ec066be7 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -9,7 +9,7 @@ QMainWindow { #ScreensCtrl { min-width:1200px; - min-height:800px; + min-height:700px; } QPushButton:focus { @@ -242,11 +242,15 @@ QTabBar::tab:focus { /************** Project Settings **************/ #projectSettings { - margin-top:42px; + margin-top:30px; +} + +#projectPreviewLabel { + margin: 10px 0 5px 0; } #projectTemplate { - margin: 55px 0 0 50px; + margin: 25px 0 0 50px; } #projectTemplateLabel { font-size:16px; diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index dec1c9a257..c7df00f423 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -11,19 +11,28 @@ #include #include #include +#include #include #include #include #include +#include namespace O3DE::ProjectManager { EngineSettingsScreen::EngineSettingsScreen(QWidget* parent) : ScreenWidget(parent) { - auto* layout = new QVBoxLayout(); + QScrollArea* scrollArea = new QScrollArea(this); + scrollArea->setWidgetResizable(true); + + QWidget* scrollWidget = new QWidget(this); + scrollArea->setWidget(scrollWidget); + + QVBoxLayout* layout = new QVBoxLayout(scrollWidget); layout->setAlignment(Qt::AlignTop); + scrollWidget->setLayout(layout); setObjectName("engineSettingsScreen"); @@ -39,9 +48,18 @@ namespace O3DE::ProjectManager formTitleLabel->setObjectName("formTitleLabel"); layout->addWidget(formTitleLabel); - m_engineVersion = new FormLineEditWidget(tr("Engine Version"), engineInfo.m_version, this); - m_engineVersion->lineEdit()->setReadOnly(true); - layout->addWidget(m_engineVersion); + FormLineEditWidget* engineName = new FormLineEditWidget(tr("Engine Name"), engineInfo.m_name, this); + engineName->lineEdit()->setReadOnly(true); + layout->addWidget(engineName); + + FormLineEditWidget* engineVersion = new FormLineEditWidget(tr("Engine Version"), engineInfo.m_version, this); + engineVersion->lineEdit()->setReadOnly(true); + layout->addWidget(engineVersion); + + FormBrowseEditWidget* engineFolder = new FormBrowseEditWidget(tr("Engine Folder"), engineInfo.m_path, this); + engineFolder->lineEdit()->setReadOnly(true); + connect( engineFolder, &FormBrowseEditWidget::OnBrowse, [engineInfo]{ AzQtComponents::ShowFileOnDesktop(engineInfo.m_path); }); + layout->addWidget(engineFolder); m_thirdParty = new FormFolderBrowseEditWidget(tr("3rd Party Software Folder"), engineInfo.m_thirdPartyPath, this); m_thirdParty->lineEdit()->setValidator(new PathValidator(PathValidator::PathMode::ExistingFolder, this)); @@ -71,7 +89,11 @@ namespace O3DE::ProjectManager connect(m_defaultProjectTemplates->lineEdit(), &QLineEdit::textChanged, this, &EngineSettingsScreen::OnTextChanged); layout->addWidget(m_defaultProjectTemplates); - setLayout(layout); + QVBoxLayout* mainLayout = new QVBoxLayout(); + mainLayout->setAlignment(Qt::AlignTop); + mainLayout->setMargin(0); + mainLayout->addWidget(scrollArea); + setLayout(mainLayout); } ProjectManagerScreen EngineSettingsScreen::GetScreenEnum() diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h index 2f16400405..1efabd4b5e 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.h @@ -29,7 +29,6 @@ namespace O3DE::ProjectManager void OnTextChanged(); private: - FormLineEditWidget* m_engineVersion; FormBrowseEditWidget* m_thirdParty; FormBrowseEditWidget* m_defaultProjects; FormBrowseEditWidget* m_defaultGems; diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp index 8cd28fcbb4..fe101cf37a 100644 --- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp +++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.cpp @@ -20,7 +20,8 @@ namespace O3DE::ProjectManager setObjectName("formBrowseEditWidget"); QPushButton* browseButton = new QPushButton(this); - connect(browseButton, &QPushButton::pressed, this, &FormBrowseEditWidget::HandleBrowseButton); + connect( browseButton, &QPushButton::pressed, [this]{ emit OnBrowse(); }); + connect( this, &FormBrowseEditWidget::OnBrowse, this, &FormBrowseEditWidget::HandleBrowseButton); m_frameLayout->addWidget(browseButton); } @@ -34,7 +35,7 @@ namespace O3DE::ProjectManager int key = event->key(); if (key == Qt::Key_Return || key == Qt::Key_Enter) { - HandleBrowseButton(); + emit OnBrowse(); } } diff --git a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h index a1f6948ce9..179fe03253 100644 --- a/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h +++ b/Code/Tools/ProjectManager/Source/FormBrowseEditWidget.h @@ -24,10 +24,13 @@ namespace O3DE::ProjectManager explicit FormBrowseEditWidget(const QString& labelText = "", QWidget* parent = nullptr); ~FormBrowseEditWidget() = default; + signals: + void OnBrowse(); + protected: void keyPressEvent(QKeyEvent* event) override; protected slots: - virtual void HandleBrowseButton() = 0; + virtual void HandleBrowseButton() {}; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 35ea67bdff..98121d7cd2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -80,7 +80,7 @@ namespace O3DE::ProjectManager void GemCatalogScreen::ReinitForProject(const QString& projectPath) { - m_gemModel->clear(); + m_gemModel->Clear(); m_gemsToRegisterWithProject.clear(); FillModel(projectPath); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 81598f5a6a..fb228c0b4a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -68,6 +68,7 @@ namespace O3DE::ProjectManager void GemModel::Clear() { clear(); + m_nameToIndexMap.clear(); } void GemModel::UpdateGemDependencies() diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp index 6f7f7e1bed..3bfc07c5b0 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectSettingsScreen.cpp @@ -36,6 +36,7 @@ namespace O3DE::ProjectManager QLabel* projectPreviewLabel = new QLabel(tr("Select an image (PNG). Minimum %1 x %2 pixels.") .arg(QString::number(ProjectPreviewImageWidth), QString::number(ProjectPreviewImageHeight))); + projectPreviewLabel->setObjectName("projectPreviewLabel"); previewExtrasLayout->addWidget(projectPreviewLabel); m_projectPreviewImage = new QLabel(this); From 5db6ffb6f3a0a5bd370785c0ae3778679c8b0bfc Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 29 Oct 2021 09:21:20 -0700 Subject: [PATCH 102/200] Disable custom titlebar on Mac, Linux, fix resize (#4973) (#5114) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/CMakeLists.txt | 1 + .../Platform/Linux/PAL_linux_files.cmake | 2 ++ .../Platform/Linux/ProjectManager_Traits_Linux.h | 11 +++++++++++ .../Platform/Linux/ProjectManager_Traits_Platform.h | 11 +++++++++++ .../ProjectManager/Platform/Mac/PAL_mac_files.cmake | 2 ++ .../Platform/Mac/ProjectManager_Traits_Mac.h | 11 +++++++++++ .../Platform/Mac/ProjectManager_Traits_Platform.h | 11 +++++++++++ .../Platform/Windows/PAL_windows_files.cmake | 2 ++ .../Platform/Windows/ProjectManager_Traits_Platform.h | 11 +++++++++++ .../Platform/Windows/ProjectManager_Traits_Windows.h | 11 +++++++++++ Code/Tools/ProjectManager/Source/Application.cpp | 7 ++++++- 11 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h create mode 100644 Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h create mode 100644 Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h diff --git a/Code/Tools/ProjectManager/CMakeLists.txt b/Code/Tools/ProjectManager/CMakeLists.txt index d34abcbc6c..a47ccb62c9 100644 --- a/Code/Tools/ProjectManager/CMakeLists.txt +++ b/Code/Tools/ProjectManager/CMakeLists.txt @@ -34,6 +34,7 @@ ly_add_target( INCLUDE_DIRECTORIES PRIVATE Source + Platform/${PAL_PLATFORM_NAME} BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core diff --git a/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake b/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake index 11222602d5..c3acd44f9b 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake +++ b/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_files.cmake @@ -11,4 +11,6 @@ set(FILES ProjectBuilderWorker_linux.cpp ProjectUtils_linux.cpp ProjectManagerDefs_linux.cpp + ProjectManager_Traits_Platform.h + ProjectManager_Traits_Linux.h ) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h new file mode 100644 index 0000000000..7c0543361f --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h @@ -0,0 +1,11 @@ +/* + * 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 + +#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h new file mode 100644 index 0000000000..97aee25507 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Platform.h @@ -0,0 +1,11 @@ +/* + * 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 + +#include diff --git a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake index 54b35f0d3c..6d4d453f21 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake +++ b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_files.cmake @@ -11,4 +11,6 @@ set(FILES ProjectBuilderWorker_mac.cpp ProjectUtils_mac.cpp ProjectManagerDefs_mac.cpp + ProjectManager_Traits_Platform.h + ProjectManager_Traits_Mac.h ) diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h new file mode 100644 index 0000000000..7c0543361f --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h @@ -0,0 +1,11 @@ +/* + * 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 + +#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h new file mode 100644 index 0000000000..dc77e77fd0 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Platform.h @@ -0,0 +1,11 @@ +/* + * 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 + +#include diff --git a/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake b/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake index d95b0d2502..22b4614ddf 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake +++ b/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_files.cmake @@ -11,4 +11,6 @@ set(FILES ProjectBuilderWorker_windows.cpp ProjectUtils_windows.cpp ProjectManagerDefs_windows.cpp + ProjectManager_Traits_Platform.h + ProjectManager_Traits_Windows.h ) diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h new file mode 100644 index 0000000000..f5eac50dbc --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Platform.h @@ -0,0 +1,11 @@ +/* + * 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 + +#include diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h new file mode 100644 index 0000000000..e6422b5a77 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h @@ -0,0 +1,11 @@ +/* + * 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 + +#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index a7e4805ce9..29e0df3c3a 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -194,8 +195,12 @@ namespace O3DE::ProjectManager // set stylesheet after creating the main window or their styles won't get updated AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:ProjectManager.qss")); - // the decoration wrapper is intended to remember window positioning and sizing + // the decoration wrapper is intended to remember window positioning and sizing +#if AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR auto wrapper = new AzQtComponents::WindowDecorationWrapper(); +#else + auto wrapper = new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionDisabled); +#endif wrapper->setGuest(m_mainWindow.data()); // show the main window here to apply the stylesheet before restoring geometry or we From 4ccbb964f3508824c75a8e0a78aa4da582b510c5 Mon Sep 17 00:00:00 2001 From: Tommy Walton Date: Fri, 29 Oct 2021 10:53:31 -0700 Subject: [PATCH 103/200] Add missing dependencies to pass builder (#4884) (#5099) * Adding shaders and attimage files as runtime depenencies for pass files, so that they are included in asset bundles. Also using the correct job key for attimage files. Signed-off-by: Tommy Walton * Use a reference to avoid a copy Signed-off-by: Tommy Walton * Bumping the AnyAsset builder version Signed-off-by: Tommy Walton * Revert "Bumping the AnyAsset builder version" This reverts commit 778798ae9cdd93ebe93248b3113e4cfb7609020d. Signed-off-by: Tommy Walton --- .../Source/RPI.Builders/Pass/PassBuilder.cpp | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp index d5e243c687..6a0b10633e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/Pass/PassBuilder.cpp @@ -10,8 +10,8 @@ #include #include - #include +#include #include #include @@ -33,11 +33,27 @@ namespace AZ static const char* PassAssetExtension = "pass"; } + namespace PassBuilderNamespace + { + enum PassDependencies + { + Shader, + AttachmentImage, + Count + }; + + static const AZStd::tuple DependencyExtensionJobKeyTable[PassDependencies::Count] = + { + {".shader", "Shader Asset"}, + {".attimage", "Any Asset Builder"} + }; + } + void PassBuilder::RegisterBuilder() { AssetBuilderSDK::AssetBuilderDesc builder; builder.m_name = PassBuilderJobKey; - builder.m_version = 13; // antonmic: making .pass files declare dependency on shaders they reference + builder.m_version = 14; // making .pass files emit product dependencies for the shaders they reference so they are picked up by the asset bundler builder.m_busId = azrtti_typeid(); builder.m_createJobFunction = AZStd::bind(&PassBuilder::CreateJobs, this, AZStd::placeholders::_1, AZStd::placeholders::_2); builder.m_processJobFunction = AZStd::bind(&PassBuilder::ProcessJob, this, AZStd::placeholders::_1, AZStd::placeholders::_2); @@ -104,8 +120,27 @@ namespace AZ } } + bool SetJobKeyForExtension(const AZStd::string& filePath, FindPassReferenceAssetParams& params) + { + AZStd::string extension; + StringFunc::Path::GetExtension(filePath.c_str(), extension); + for (const auto& [dependencyExtension, jobKey] : PassBuilderNamespace::DependencyExtensionJobKeyTable) + { + if (extension == dependencyExtension) + { + params.jobKey = jobKey; + return true; + } + } + + AZ_Error(PassBuilderName, false, "PassBuilder found a dependency with extension '%s', but does not know the corresponding job key. Add the job key for that extension to SetJobKeyForExtension in PassBuilder.cpp", extension.c_str()); + params.jobKey = "Unknown"; + return false; + } + // Helper function to find all assetId's and object references - bool FindReferencedAssets(FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job) + bool FindReferencedAssets( + FindPassReferenceAssetParams& params, AssetBuilderSDK::JobDescriptor* job, AZStd::vector* productDependencies) { SerializeContext::ErrorHandler errorLogger; errorLogger.Reset(); @@ -129,8 +164,8 @@ namespace AZ if (job != nullptr) // Create Job Phase { params.dependencySourceFile = path; - bool dependencyAddedSuccessfully = AddDependency(params, job); - success = dependencyAddedSuccessfully && success; + success &= SetJobKeyForExtension(path, params); + success &= AddDependency(params, job); } else // Process Job Phase { @@ -139,6 +174,9 @@ namespace AZ if (assetIdOutcome) { assetReference->m_assetId = assetIdOutcome.GetValue(); + productDependencies->push_back( + AssetBuilderSDK::ProductDependency{assetReference->m_assetId, AZ::Data::ProductDependencyInfo::CreateFlags(Data::AssetLoadBehavior::NoLoad)} + ); } else { @@ -223,9 +261,9 @@ namespace AZ params.passAssetSourceFile = request.m_sourceFile; params.passAssetUuid = passAssetUuid; params.serializeContext = serializeContext; - params.jobKey = "Shader Asset"; + params.jobKey = "Unknown"; - if (!FindReferencedAssets(params, &job)) + if (!FindReferencedAssets(params, &job, nullptr)) { return; } @@ -287,9 +325,10 @@ namespace AZ params.passAssetSourceFile = request.m_sourceFile; params.passAssetUuid = passAssetUuid; params.serializeContext = serializeContext; - params.jobKey = "Shader Asset"; + params.jobKey = "Unknown"; - if (!FindReferencedAssets(params, nullptr)) + AZStd::vector productDependencies; + if (!FindReferencedAssets(params, nullptr, &productDependencies)) { return; } @@ -313,6 +352,7 @@ namespace AZ // --- Save output product(s) to response --- AssetBuilderSDK::JobProduct jobProduct(destPath, PassAsset::RTTI_Type(), 0); + jobProduct.m_dependencies = productDependencies; jobProduct.m_dependenciesHandled = true; response.m_outputProducts.push_back(jobProduct); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; From 2f38873e03d1f512ec0167073585390b5824d1d9 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 29 Oct 2021 13:55:32 -0700 Subject: [PATCH 104/200] Adding logs for successful steps occurring in the editor-server process. AutomatedTesting will expect these logs and can be helpful to narrow down any test fails Signed-off-by: Gene Walters --- .../editor_python_test_tools/utils.py | 35 +++++++++++++++---- .../Editor/MultiplayerEditorConnection.cpp | 10 ++++-- .../MultiplayerEditorSystemComponent.cpp | 2 ++ 3 files changed, 38 insertions(+), 9 deletions(-) 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 d6f33a1726..77143a8ae7 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -76,21 +76,42 @@ class TestHelper: :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() - general.idle_wait_frames(1) - # Make sure the server launcher binary exists - unexpected_line = "LaunchEditorServer failed! The ServerLauncher binary is missing!" - found_lines = [printInfo.message.strip() for printInfo in section_tracer.errors] - found_unexpected_lines = [x for x in found_lines if unexpected_line in x] - Report.critical_result(("ServerLauncher exists.", "ServerLauncher does not exist!"), not found_unexpected_lines) + # make sure the server launcher binary exists + wait_for_critical_unexpected_line("LaunchEditorServer failed! The ServerLauncher binary is missing!", section_tracer.errors, 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, 30.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, 30.0) - TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 30.0) + TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 10.0) Report.critical_result(msgtuple_success_fail, multiplayer.PythonEditorFuncs_is_in_game_mode()) @staticmethod diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index d2b0ca7095..2a62e35e3a 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -180,8 +180,14 @@ namespace Multiplayer } // Connect the Editor to the editor server for Multiplayer simulation - AZ::Interface::Get()->Connect(editorsv_serveraddr.c_str(), sv_port); - + if (AZ::Interface::Get()->Connect(editorsv_serveraddr.c_str(), sv_port)) + { + AZ_Printf("MultiplayerEditorConnection", "Editor-server ready. Editor has successfully connected to the editor-server's network simulation.") + } + else + { + AZ_Warning("MultiplayerEditorConnection", false, "MultiplayerEditorConnection::HandleRequest for EditorServerReady failed! Connecting to the editor-server's network simulation failed.") + } return true; } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index ed886e8b57..388e38dee7 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -328,6 +328,8 @@ namespace Multiplayer return; } + AZ_Printf("MultiplayerEditor", "Editor is sending the editor-server the level data packet.") + const AZStd::vector>& assetData = prefabEditorEntityOwnershipInterface->GetPlayInEditorAssetData(); AZStd::vector buffer; From b2e6711196295a81f47224d1578aa939afb47133 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 29 Oct 2021 14:45:25 -0700 Subject: [PATCH 105/200] [profiler_capture_api] fixed clang compile error Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/Trace.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp index 1dd9d0f0f9..b9e4003500 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Trace.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Trace.cpp @@ -55,7 +55,7 @@ namespace AZ::Debug // 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 From 22820b6a90ec11063b1308888972698d260b3c59 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Fri, 29 Oct 2021 15:13:20 -0700 Subject: [PATCH 106/200] Update snapshots list to stablization/2110 Signed-off-by: Mike Chang --- scripts/build/Jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 35f6f9a81c..04e249255f 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -16,7 +16,7 @@ EMPTY_JSON = readJSON text: '{}' ENGINE_REPOSITORY_NAME = 'o3de' // Branches with build snapshots -BUILD_SNAPSHOTS = ['development', 'stabilization/2106'] +BUILD_SNAPSHOTS = ['development', 'stabilization/2110'] // Build snapshots with empty snapshot (for use with 'SNAPSHOT' pipeline paramater) BUILD_SNAPSHOTS_WITH_EMPTY = BUILD_SNAPSHOTS + '' From 4721f44b928365e930124d3cefa49cecacfe325c Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 29 Oct 2021 17:19:38 -0700 Subject: [PATCH 107/200] [profiler_capture_api] more changes based on PR feedback Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Debug/Profiler.cpp | 8 ++------ Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp | 3 ++- Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp | 5 +---- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp index 3b6b3b7e7a..0cb77b2d6e 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp @@ -16,12 +16,8 @@ namespace AZ::Debug { AZStd::string GenerateOutputFile(const char* nameHint) { - AZStd::string timeString; - AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation(); - - return AZStd::string::format("%s/capture_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); + return AZStd::string::format("%s/capture_%s_%lld.json", captureOutput.c_str(), nameHint, AZStd::GetTimeNowSecond()); } void ProfilerCaptureFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) @@ -41,7 +37,7 @@ namespace AZ::Debug { AZStd::string captureFile = GenerateOutputFile("multi"); AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); - profilerSystem->StartCapture(captureFile); + profilerSystem->StartCapture(AZStd::move(captureFile)); } } AZ_CONSOLEFREEFUNC(ProfilerStartCapture, AZ::ConsoleFunctorFlags::DontReplicate, "Start a multi-frame capture of profiling data"); diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp index 3455400cfe..42151a6996 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerReflection.cpp @@ -74,7 +74,8 @@ namespace AZ::Debug ->Method("GetCaptureLocation", [](ProfilerSystemScriptProxy*) -> AZStd::string { - return AZStd::string(GetProfilerCaptureLocation().c_str()); + AZ::IO::FixedMaxPathString captureOutput = GetProfilerCaptureLocation(); + return AZStd::string(captureOutput.c_str(), captureOutput.length()); }) ->Method("IsActive", ProfilerSystemScriptProxy::WrapMethod<&ProfilerRequests::IsActive>()) diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index e1a734136b..26c2f9f974 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -402,13 +402,10 @@ namespace Profiler AZStd::string ImGuiCpuProfiler::GenerateOutputFile(const char* nameHint) { - AZStd::string timeString; - AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - AZ::IO::FixedMaxPathString captureOutput = AZ::Debug::GetProfilerCaptureLocation(); const AZ::IO::FixedMaxPathString frameDataFilePath = - AZ::IO::FixedMaxPathString::format("%s/cpu_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); + AZ::IO::FixedMaxPathString::format("%s/cpu_%s_%lld.json", captureOutput.c_str(), nameHint, AZStd::GetTimeNowSecond()); AZ::IO::FileIOBase::GetInstance()->ResolvePath(m_lastCapturedFilePath, frameDataFilePath.c_str()); From 1ec34f6123e029cd2a27c3c8003e03db0ac52145 Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Fri, 29 Oct 2021 21:11:53 -0700 Subject: [PATCH 108/200] Fix typo when calling upload_to_s3.py (#5139) Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 35f6f9a81c..e00530d0b7 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -450,7 +450,7 @@ def UploadAPLogs(Map options, String branchName, String jobName, String workspac def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + "--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName} " + - "--extra-args {\"ACL\": \"bucket-owner-full-control\"}" + "--extra_args {\"ACL\": \"bucket-owner-full-control\"}" palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) } } From 8c0dbe4b33ed958fad24835fb34c81efaae65335 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Sat, 30 Oct 2021 12:39:40 -0700 Subject: [PATCH 109/200] missed escaping these variables and breaks runtime dependencines in the install layout (#5149) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index df19ad0e78..803edb7b1d 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -528,7 +528,7 @@ function(ly_setup_runtime_dependencies) ly_install(CODE "function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME file_name) - if(NOT EXISTS ${target_directory}/${file_name}) + if(NOT EXISTS \${target_directory}/\${file_name}) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endif() endfunction()" From 799290aefc4e1931c8cfc8a37800db3f67c4bd6d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 30 Oct 2021 17:36:07 -0500 Subject: [PATCH 110/200] Created custom JSON serializer for editor material component The editor component contains an editor specific, dynamically generated version of the material slots to display all the possible options, organize properties for the user interface, and add custom actions. The critical data is already stored inside of the component controller configuration, which only stores a map of modified or overridden values. This change disables serialization of the redundant data for prefabs. Signed-off-by: Guthrie Adams --- .../Material/EditorMaterialComponent.cpp | 26 +++-- .../Source/Material/EditorMaterialComponent.h | 2 + .../EditorMaterialComponentSerializer.cpp | 109 ++++++++++++++++++ .../EditorMaterialComponentSerializer.h | 41 +++++++ ...egration_commonfeatures_editor_files.cmake | 2 + 5 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp index 94beeb2430..7e6b3e4e4c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.cpp @@ -6,23 +6,24 @@ * */ -#include -#include - -#include -#include -#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include #include +#include AZ_POP_DISABLE_WARNING namespace AZ @@ -59,7 +60,12 @@ namespace AZ BaseClass::Reflect(context); EditorMaterialComponentSlot::Reflect(context); - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) + if (auto jsonContext = azrtti_cast(context)) + { + jsonContext->Serializer()->HandlesType(); + } + + if (auto serializeContext = azrtti_cast(context)) { serializeContext->RegisterGenericType(); serializeContext->RegisterGenericType(); @@ -76,7 +82,7 @@ namespace AZ serializeContext->RegisterGenericType, AZStd::equal_to, AZStd::allocator>>(); serializeContext->RegisterGenericType, AZStd::equal_to, AZStd::allocator>>(); - if (AZ::EditContext* editContext = serializeContext->GetEditContext()) + if (auto editContext = serializeContext->GetEditContext()) { editContext->Class( "Material", "The material component specifies the material to use for this entity") @@ -129,7 +135,7 @@ namespace AZ } } - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + if (auto behaviorContext = azrtti_cast(context)) { behaviorContext->ConstantProperty("EditorMaterialComponentTypeId", BehaviorConstant(Uuid(EditorMaterialComponentTypeId))) ->Attribute(AZ::Script::Attributes::Module, "render") diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h index ce21ae82ac..4cd7870be5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponent.h @@ -27,6 +27,8 @@ namespace AZ , public EditorMaterialSystemComponentNotificationBus::Handler { public: + friend class JsonEditorMaterialComponentSerializer; + using BaseClass = EditorRenderComponentAdapter; AZ_EDITOR_COMPONENT(EditorMaterialComponent, EditorMaterialComponentTypeId, BaseClass); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp new file mode 100644 index 0000000000..955fd7a97f --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp @@ -0,0 +1,109 @@ +/* + * 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 + +namespace AZ +{ + namespace Render + { + AZ_CLASS_ALLOCATOR_IMPL(JsonEditorMaterialComponentSerializer, AZ::SystemAllocator, 0); + + AZ::JsonSerializationResult::Result JsonEditorMaterialComponentSerializer::Load( + void* outputValue, + [[maybe_unused]] const AZ::Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) + { + namespace JSR = AZ::JsonSerializationResult; + + AZ_Assert( + azrtti_typeid() == outputValueTypeId, + "Unable to deserialize EditorMaterialComponent from json because the provided type is %s.", + outputValueTypeId.ToString().c_str()); + + auto componentInstance = reinterpret_cast(outputValue); + AZ_Assert(componentInstance, "Output value for JsonEditorMaterialComponentSerializer can't be null."); + + JSR::ResultCode result(JSR::Tasks::ReadField); + + result.Combine(ContinueLoadingFromJsonObjectField( + &componentInstance->m_id, azrtti_typeidm_id)>(), inputValue, "Id", context)); + + result.Combine(ContinueLoadingFromJsonObjectField( + &componentInstance->m_controller, azrtti_typeidm_controller)>(), inputValue, "Controller", + context)); + + result.Combine(ContinueLoadingFromJsonObjectField( + &componentInstance->m_materialSlotsByLodEnabled, azrtti_typeidm_materialSlotsByLodEnabled)>(), + inputValue, "materialSlotsByLodEnabled", context)); + + return context.Report( + result, + result.GetProcessing() != JSR::Processing::Halted ? "Successfully loaded EditorMaterialComponent information." + : "Failed to load EditorMaterialComponent information."); + } + + AZ::JsonSerializationResult::Result JsonEditorMaterialComponentSerializer::Store( + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + [[maybe_unused]] const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) + { + namespace JSR = AZ::JsonSerializationResult; + + AZ_Assert( + azrtti_typeid() == valueTypeId, + "Unable to Serialize EditorMaterialComponent because the provided type is %s.", + valueTypeId.ToString().c_str()); + + auto componentInstance = reinterpret_cast(inputValue); + AZ_Assert(componentInstance, "Input value for JsonEditorMaterialComponentSerializer can't be null."); + auto defaultComponentInstance = reinterpret_cast(defaultValue); + + JSR::ResultCode result(JSR::Tasks::WriteValue); + { + AZ::ScopedContextPath subPathName(context, "m_id"); + const auto componentId = &componentInstance->m_id; + const auto defaultComponentId = defaultComponentInstance ? &defaultComponentInstance->m_id : nullptr; + + result.Combine(ContinueStoringToJsonObjectField( + outputValue, "Id", componentId, defaultComponentId, azrtti_typeidm_id)>(), context)); + } + + { + AZ::ScopedContextPath subPathName(context, "Controller"); + const auto controller = &componentInstance->m_controller; + const auto defaultController = defaultComponentInstance ? &defaultComponentInstance->m_controller : nullptr; + + result.Combine(ContinueStoringToJsonObjectField( + outputValue, "Controller", controller, defaultController, azrtti_typeidm_controller)>(), + context)); + } + + { + AZ::ScopedContextPath subPathName(context, "materialSlotsByLodEnabled"); + const auto enabled = &componentInstance->m_materialSlotsByLodEnabled; + const auto defaultEnabled = defaultComponentInstance ? &defaultComponentInstance->m_materialSlotsByLodEnabled : nullptr; + + result.Combine(ContinueStoringToJsonObjectField( + outputValue, "materialSlotsByLodEnabled", enabled, defaultEnabled, + azrtti_typeidm_materialSlotsByLodEnabled)>(), context)); + } + + return context.Report( + result, + result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored EditorMaterialComponent information." + : "Failed to store EditorMaterialComponent information."); + } + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h new file mode 100644 index 0000000000..6689d11e84 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h @@ -0,0 +1,41 @@ +/* + * 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 + +#include +#include + +namespace AZ +{ + namespace Render + { + // JsonEditorMaterialComponentSerializer skips serialization of EditorMaterialComponentSlot(s) which are only needed at runtime in + // the editor + class JsonEditorMaterialComponentSerializer : public AZ::BaseJsonSerializer + { + public: + AZ_RTTI(JsonEditorMaterialComponentSerializer, "{D354FE3C-34D2-4E80-B3F9-49450D252336}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + AZ::JsonSerializationResult::Result Load( + void* outputValue, + const AZ::Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, + AZ::JsonDeserializerContext& context) override; + + AZ::JsonSerializationResult::Result Store( + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + const AZ::Uuid& valueTypeId, + AZ::JsonSerializerContext& context) override; + }; + + } // namespace Render +} // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 2714b65a56..0dea725d70 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -31,6 +31,8 @@ set(FILES Source/ImageBasedLights/EditorImageBasedLightComponent.cpp Source/Material/EditorMaterialComponent.cpp Source/Material/EditorMaterialComponent.h + Source/Material/EditorMaterialComponentSerializer.cpp + Source/Material/EditorMaterialComponentSerializer.h Source/Material/EditorMaterialComponentUtil.cpp Source/Material/EditorMaterialComponentUtil.h Source/Material/EditorMaterialComponentSlot.cpp From c79bf7a0c187459c94a4acf5bd0a6d41fe76ca3b Mon Sep 17 00:00:00 2001 From: rhhong Date: Sat, 30 Oct 2021 22:37:05 -0700 Subject: [PATCH 111/200] load render option in atom render plugin and use render actor settings in atom debug draw Signed-off-by: rhhong --- .../Code/Source/AtomActorDebugDraw.cpp | 83 ++++++++++--------- .../Code/Source/AtomActorDebugDraw.h | 7 +- .../Tools/EMStudio/AnimViewportRenderer.cpp | 19 ++--- .../Tools/EMStudio/AnimViewportRenderer.h | 5 +- .../Tools/EMStudio/AnimViewportWidget.cpp | 12 ++- .../Code/Tools/EMStudio/AnimViewportWidget.h | 6 +- .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 27 +++++- .../Code/Tools/EMStudio/AtomRenderPlugin.h | 12 ++- .../EMotionFX/Source/EMotionFXManager.cpp | 10 +++ .../Code/EMotionFX/Source/EMotionFXManager.h | 22 +++++ .../Source/RenderPlugin/RenderOptions.cpp | 24 +++++- .../Source/RenderPlugin/RenderOptions.h | 8 ++ .../Rendering/RenderActorSettings.h | 34 ++++++++ .../Code/emotionfx_shared_files.cmake | 1 + 14 files changed, 203 insertions(+), 67 deletions(-) create mode 100644 Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp index 1325455cd9..4b06fc5753 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,7 @@ namespace AZ::Render const EMotionFX::Pose* pose = instance->GetTransformData()->GetCurrentPose(); const size_t geomLODLevel = instance->GetLODLevel(); const size_t numEnabled = instance->GetNumEnabledNodes(); + const float scaleMultiplier = CalculateScaleMultiplier(instance); for (size_t i = 0; i < numEnabled; ++i) { EMotionFX::Node* node = instance->GetActor()->GetSkeleton()->GetNode(instance->GetEnabledNode(i)); @@ -83,19 +85,27 @@ namespace AZ::Render continue; } - RenderNormals(mesh, globalTM, renderVertexNormals, renderFaceNormals); + RenderNormals(mesh, globalTM, renderVertexNormals, renderFaceNormals, scaleMultiplier); if (renderTangents) { - RenderTangents(mesh, globalTM); + RenderTangents(mesh, globalTM, scaleMultiplier); } if (renderWireframe) { - RenderWireframe(mesh, globalTM); + RenderWireframe(mesh, globalTM, scaleMultiplier); } } } } + float AtomActorDebugDraw::CalculateScaleMultiplier(EMotionFX::ActorInstance* instance) const + { + const AZ::Aabb aabb = instance->GetAabb(); + const float aabbRadius = AZ::Vector3(aabb.GetMax() - aabb.GetMin()).GetLength() * 0.5f; + // Scale the multiplier down to 1% of the character size, that looks pretty nice on all models + return aabbRadius * 0.01f; + } + void AtomActorDebugDraw::PrepareForMesh(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) { // Check if we have already prepared for the given mesh @@ -128,7 +138,8 @@ namespace AZ::Render { RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); const AZ::Aabb& aabb = instance->GetAabb(); - auxGeom->DrawAabb(aabb, AZ::Color(0.0f, 1.0f, 1.0f, 1.0f), RPI::AuxGeomDraw::DrawStyle::Line); + const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); + auxGeom->DrawAabb(aabb, renderActorSettings.m_staticAABBColor, RPI::AuxGeomDraw::DrawStyle::Line); } void AtomActorDebugDraw::RenderSkeleton(EMotionFX::ActorInstance* instance) @@ -166,11 +177,11 @@ namespace AZ::Render m_auxVertices.emplace_back(bonePos); } - const AZ::Color skeletonColor(0.604f, 0.804f, 0.196f, 1.0f); + const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &skeletonColor; + lineArgs.m_colors = &renderActorSettings.m_lineSkeletonColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); @@ -218,7 +229,7 @@ namespace AZ::Render auxGeom->DrawLines(lineArgs); } - void AtomActorDebugDraw::RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals) + void AtomActorDebugDraw::RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals, float scaleMultiplier) { if (!mesh) { @@ -236,11 +247,7 @@ namespace AZ::Render return; } - // TODO: Move line color to a render setting. - const float faceNormalsScale = 0.01f; - const AZ::Color colorFaceNormals = AZ::Colors::Lime; - const float vertexNormalsScale = 0.01f; - const AZ::Color colorVertexNormals = AZ::Colors::Orange; + const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); PrepareForMesh(mesh, worldTM); @@ -277,14 +284,14 @@ namespace AZ::Render const AZ::Vector3 normalPos = (posA + posB + posC) * (1.0f / 3.0f); m_auxVertices.emplace_back(normalPos); - m_auxVertices.emplace_back(normalPos + (normalDir * faceNormalsScale)); + m_auxVertices.emplace_back(normalPos + (normalDir * renderActorSettings.m_faceNormalsScale * scaleMultiplier)); } } RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &colorFaceNormals; + lineArgs.m_colors = &renderActorSettings.m_faceNormalsColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); @@ -307,7 +314,8 @@ namespace AZ::Render { const uint32 vertexIndex = j + startVertex; const AZ::Vector3& position = m_worldSpacePositions[vertexIndex]; - const AZ::Vector3 normal = worldTM.TransformVector(normals[vertexIndex]).GetNormalizedSafe() * vertexNormalsScale; + const AZ::Vector3 normal = worldTM.TransformVector(normals[vertexIndex]).GetNormalizedSafe() * + renderActorSettings.m_vertexNormalsScale * scaleMultiplier; m_auxVertices.emplace_back(position); m_auxVertices.emplace_back(position + normal); @@ -317,14 +325,14 @@ namespace AZ::Render RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &colorVertexNormals; + lineArgs.m_colors = &renderActorSettings.m_vertexNormalsColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); } } - void AtomActorDebugDraw::RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) + void AtomActorDebugDraw::RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier) { if (!mesh) { @@ -337,11 +345,7 @@ namespace AZ::Render return; } - // TODO: Move line color to a render setting. - const AZ::Color colorTangents = AZ::Colors::Red; - const AZ::Color mirroredBitangentColor = AZ::Colors::Yellow; - const AZ::Color colorBitangents = AZ::Colors::White; - const float scale = 0.01f; + const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); // Get the tangents and check if this mesh actually has tangents AZ::Vector4* tangents = static_cast(mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_TANGENTS)); @@ -380,23 +384,23 @@ namespace AZ::Render bitangent = (worldTM.TransformVector(bitangent)).GetNormalizedSafe(); m_auxVertices.emplace_back(m_worldSpacePositions[i]); - m_auxColors.emplace_back(colorTangents); - m_auxVertices.emplace_back(m_worldSpacePositions[i] + (tangent * scale)); - m_auxColors.emplace_back(colorTangents); + m_auxColors.emplace_back(renderActorSettings.m_tangentsColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (tangent * renderActorSettings.m_tangentsScale * scaleMultiplier)); + m_auxColors.emplace_back(renderActorSettings.m_tangentsColor); if (tangents[i].GetW() < 0.0f) { m_auxVertices.emplace_back(m_worldSpacePositions[i]); - m_auxColors.emplace_back(mirroredBitangentColor); - m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * scale)); - m_auxColors.emplace_back(mirroredBitangentColor); + m_auxColors.emplace_back(renderActorSettings.m_mirroredBitangentsColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * renderActorSettings.m_tangentsScale * scaleMultiplier)); + m_auxColors.emplace_back(renderActorSettings.m_mirroredBitangentsColor); } else { m_auxVertices.emplace_back(m_worldSpacePositions[i]); - m_auxColors.emplace_back(colorBitangents); - m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * scale)); - m_auxColors.emplace_back(colorBitangents); + m_auxColors.emplace_back(renderActorSettings.m_bitangentsColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * renderActorSettings.m_tangentsScale * scaleMultiplier)); + m_auxColors.emplace_back(renderActorSettings.m_bitangentsColor); } } @@ -409,7 +413,7 @@ namespace AZ::Render auxGeom->DrawLines(lineArgs); } - void AtomActorDebugDraw::RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM) + void AtomActorDebugDraw::RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier) { // Check if the mesh is valid and skip the node in case it's not if (!mesh) @@ -423,12 +427,10 @@ namespace AZ::Render return; } + const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); PrepareForMesh(mesh, worldTM); - const float scale = 0.01f; - const AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); - const AZ::Color vertexColor = AZ::Color(0.8f, 0.24f, 0.88f, 1.0f); const size_t numSubMeshes = mesh->GetNumSubMeshes(); for (uint32 subMeshIndex = 0; subMeshIndex < numSubMeshes; ++subMeshIndex) @@ -448,9 +450,12 @@ namespace AZ::Render const uint32 indexB = indices[triangleStartIndex + 1] + startVertex; const uint32 indexC = indices[triangleStartIndex + 2] + startVertex; - const AZ::Vector3 posA = m_worldSpacePositions[indexA] + normals[indexA] * scale; - const AZ::Vector3 posB = m_worldSpacePositions[indexB] + normals[indexB] * scale; - const AZ::Vector3 posC = m_worldSpacePositions[indexC] + normals[indexC] * scale; + const AZ::Vector3 posA = + m_worldSpacePositions[indexA] + normals[indexA] * renderActorSettings.m_wireframeScale * scaleMultiplier; + const AZ::Vector3 posB = + m_worldSpacePositions[indexB] + normals[indexB] * renderActorSettings.m_wireframeScale * scaleMultiplier; + const AZ::Vector3 posC = + m_worldSpacePositions[indexC] + normals[indexC] * renderActorSettings.m_wireframeScale * scaleMultiplier; m_auxVertices.emplace_back(posA); m_auxVertices.emplace_back(posB); @@ -465,7 +470,7 @@ namespace AZ::Render RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &vertexColor; + lineArgs.m_colors = &renderActorSettings.m_wireframeColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h index 797de16351..f674ffbb96 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h @@ -37,13 +37,14 @@ namespace AZ::Render private: + float CalculateScaleMultiplier(EMotionFX::ActorInstance* instance) const; void PrepareForMesh(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); void RenderAABB(EMotionFX::ActorInstance* instance); void RenderSkeleton(EMotionFX::ActorInstance* instance); void RenderEMFXDebugDraw(EMotionFX::ActorInstance* instance); - void RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals); - void RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); - void RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); + void RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals, float scaleMultiplier); + void RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier); + void RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier); EMotionFX::Mesh* m_currentMesh = nullptr; /**< A pointer to the mesh whose world space positions are in the pre-calculated positions buffer. NULL in case we haven't pre-calculated any positions yet. */ diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index facf7a7b12..1afae0e17b 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -37,14 +37,13 @@ #include #include #include - +#include namespace EMStudio { - static constexpr float DepthNear = 0.01f; - - AnimViewportRenderer::AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext) + AnimViewportRenderer::AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext, const RenderOptions* renderOptions) : m_windowContext(viewportContext->GetWindowContext()) + , m_renderOptions(renderOptions) { // Create a new entity context m_entityContext = AZStd::make_unique(); @@ -128,10 +127,10 @@ namespace EMStudio AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); AZ::Render::GridComponentConfig gridConfig; - gridConfig.m_gridSize = 20.0f; - gridConfig.m_axisColor = AZ::Color(0.5f, 0.5f, 0.5f, 1.0f); - gridConfig.m_primaryColor = AZ::Color(0.3f, 0.3f, 0.3f, 1.0f); - gridConfig.m_secondaryColor = AZ::Color(0.5f, 0.5f, 0.5f, 1.0f); + gridConfig.m_secondarySpacing = m_renderOptions->GetGridUnitSize(); + gridConfig.m_axisColor = m_renderOptions->GetMainAxisColor(); + gridConfig.m_primaryColor = m_renderOptions->GetGridColor(); + gridConfig.m_secondaryColor = m_renderOptions->GetSubStepColor(); auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); gridComponent->SetConfiguration(gridConfig); @@ -326,8 +325,8 @@ namespace EMStudio ->GetOrCreateExposureControlSettingsInterface(); Camera::Configuration cameraConfig; - cameraConfig.m_fovRadians = AZ::Constants::HalfPi; - cameraConfig.m_nearClipDistance = DepthNear; + cameraConfig.m_fovRadians = AZ::DegToRad(m_renderOptions->GetFOV()); + cameraConfig.m_nearClipDistance = m_renderOptions->GetNearClipPlaneDistance(); preset->ApplyLightingPreset( iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor, diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h index a4f67ddfd1..df69856355 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -39,12 +39,14 @@ namespace AZ namespace EMStudio { + class RenderOptions; + class AnimViewportRenderer { public: AZ_CLASS_ALLOCATOR(AnimViewportRenderer, AZ::SystemAllocator, 0); - AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext); + AnimViewportRenderer(AZ::RPI::ViewportContextPtr viewportContext, const RenderOptions* renderOptions); ~AnimViewportRenderer(); void Reinit(); @@ -83,6 +85,7 @@ namespace EMStudio AZ::Entity* m_iblEntity = nullptr; AZ::Entity* m_gridEntity = nullptr; AZStd::vector m_actorEntities; + const RenderOptions* m_renderOptions; AZStd::vector m_lightHandles; }; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index c6e349236f..cf7341e9ab 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -17,11 +17,13 @@ #include #include #include +#include namespace EMStudio { - AnimViewportWidget::AnimViewportWidget(QWidget* parent) - : AtomToolsFramework::RenderViewportWidget(parent) + AnimViewportWidget::AnimViewportWidget(AtomRenderPlugin* parentPlugin) + : AtomToolsFramework::RenderViewportWidget(parentPlugin->GetInnerWidget()) + , m_plugin(parentPlugin) { setObjectName(QString::fromUtf8("AtomViewportWidget")); QSizePolicy qSize(QSizePolicy::Preferred, QSizePolicy::Preferred); @@ -32,7 +34,7 @@ namespace EMStudio setAutoFillBackground(false); setStyleSheet(QString::fromUtf8("")); - m_renderer = AZStd::make_unique(GetViewportContext()); + m_renderer = AZStd::make_unique(GetViewportContext(), m_plugin->GetRenderOptions()); LoadRenderFlags(); SetupCameras(); @@ -181,8 +183,10 @@ namespace EMStudio const float height = AZStd::max(aznumeric_cast(windowSize.m_height), 1.0f); const float aspectRatio = aznumeric_cast(windowSize.m_width) / height; + const RenderOptions* renderOptions = m_plugin->GetRenderOptions(); AZ::Matrix4x4 viewToClipMatrix; - AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, aspectRatio, DepthNear, DepthFar, true); + AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::DegToRad(renderOptions->GetFOV()), aspectRatio, + renderOptions->GetNearClipPlaneDistance(), renderOptions->GetFarClipPlaneDistance(), true); viewportContext->GetDefaultView()->SetViewToClipMatrix(viewToClipMatrix); } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index e2099ea2ab..7a8ae2cf52 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -15,6 +15,7 @@ namespace EMStudio { + class AtomRenderPlugin; class AnimViewportRenderer; class AnimViewportWidget @@ -22,7 +23,7 @@ namespace EMStudio , private AnimViewportRequestBus::Handler { public: - AnimViewportWidget(QWidget* parent = nullptr); + AnimViewportWidget(AtomRenderPlugin* parentPlugin); ~AnimViewportWidget() override; AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); } @@ -45,9 +46,8 @@ namespace EMStudio void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag); static constexpr float CameraDistance = 2.0f; - static constexpr float DepthNear = 0.01f; - static constexpr float DepthFar = 100.0f; + AtomRenderPlugin* m_plugin; AZStd::unique_ptr m_renderer; AZStd::shared_ptr m_rotateCamera; AZStd::shared_ptr m_translateCamera; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index ce2e76a6c7..297bfea760 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -27,7 +27,10 @@ namespace EMStudio AtomRenderPlugin::~AtomRenderPlugin() { - + GetCommandManager()->RemoveCommandCallback(m_importActorCallback, false); + GetCommandManager()->RemoveCommandCallback(m_removeActorCallback, false); + delete m_importActorCallback; + delete m_removeActorCallback; } const char* AtomRenderPlugin::GetName() const @@ -75,6 +78,11 @@ namespace EMStudio return EMStudioPlugin::PLUGINTYPE_RENDERING; } + QWidget* AtomRenderPlugin::GetInnerWidget() + { + return m_innerWidget; + } + void AtomRenderPlugin::ReinitRenderer() { m_animViewportWidget->Reinit(); @@ -82,6 +90,8 @@ namespace EMStudio bool AtomRenderPlugin::Init() { + LoadRenderOptions(); + m_innerWidget = new QWidget(); m_dock->setWidget(m_innerWidget); @@ -91,7 +101,7 @@ namespace EMStudio verticalLayout->setMargin(0); // Add the viewport widget - m_animViewportWidget = new AnimViewportWidget(m_innerWidget); + m_animViewportWidget = new AnimViewportWidget(this); // Add the tool bar AnimViewportToolBar* toolBar = new AnimViewportToolBar(m_innerWidget); @@ -109,6 +119,19 @@ namespace EMStudio return true; } + void AtomRenderPlugin::LoadRenderOptions() + { + AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder()); + renderOptionsFilename += "EMStudioRenderOptions.cfg"; + QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this); + m_renderOptions = RenderOptions::Load(&settings); + } + + const RenderOptions* AtomRenderPlugin::GetRenderOptions() const + { + return &m_renderOptions; + } + // Command callbacks bool ReinitAtomRenderPlugin() { diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h index 1516b45e77..d87e039487 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -11,6 +11,7 @@ #if !defined(Q_MOC_RUN) #include #include +#include #include #include @@ -47,15 +48,22 @@ namespace EMStudio bool Init() override; EMStudioPlugin* Clone(); EMStudioPlugin::EPluginType GetPluginType() const override; + QWidget* GetInnerWidget(); void ReinitRenderer(); + void LoadRenderOptions(); + const RenderOptions* GetRenderOptions() const; + private: + + QWidget* m_innerWidget = nullptr; + AnimViewportWidget* m_animViewportWidget = nullptr; + RenderOptions m_renderOptions; + MCORE_DEFINECOMMANDCALLBACK(ImportActorCallback); MCORE_DEFINECOMMANDCALLBACK(RemoveActorCallback); ImportActorCallback* m_importActorCallback = nullptr; RemoveActorCallback* m_removeActorCallback = nullptr; - QWidget* m_innerWidget = nullptr; - AnimViewportWidget* m_animViewportWidget = nullptr; }; }// namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp index d5fa3867e0..af041fd316 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace EMotionFX { @@ -75,6 +76,7 @@ namespace EMotionFX gEMFX.Get()->SetRecorder (Recorder::Create()); gEMFX.Get()->SetMotionInstancePool (MotionInstancePool::Create()); gEMFX.Get()->SetDebugDraw (aznew DebugDraw()); + gEMFX.Get()->SetRenderActorSettings (new AZ::Render::RenderActorSettings()); gEMFX.Get()->SetGlobalSimulationSpeed (1.0f); // set the number of threads @@ -123,6 +125,7 @@ namespace EMotionFX m_recorder = nullptr; m_motionInstancePool = nullptr; m_debugDraw = nullptr; + m_renderActorSettings = nullptr; m_unitType = MCore::Distance::UNITTYPE_METERS; m_globalSimulationSpeed = 1.0f; m_isInEditorMode = false; @@ -167,6 +170,8 @@ namespace EMotionFX delete m_debugDraw; m_debugDraw = nullptr; + delete m_renderActorSettings; + m_renderActorSettings = nullptr; m_eventManager->Destroy(); m_eventManager = nullptr; @@ -311,6 +316,11 @@ namespace EMotionFX m_debugDraw = draw; } + void EMotionFXManager::SetRenderActorSettings(AZ::Render::RenderActorSettings* settings) + { + m_renderActorSettings = settings; + } + // set the motion instance pool void EMotionFXManager::SetMotionInstancePool(MotionInstancePool* pool) { diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h index d5c5247de6..41b57cb2d8 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h @@ -19,6 +19,10 @@ MCORE_FORWARD_DECLARE(MemoryTracker); +namespace AZ::Render +{ + class RenderActorSettings; +} namespace EMotionFX { @@ -184,6 +188,15 @@ namespace EMotionFX */ MCORE_INLINE DebugDraw* GetDebugDraw() const { return m_debugDraw; } + /** + * Get the render actor settings + * @result A pointer to global render actor settings. + */ + MCORE_INLINE AZ::Render::RenderActorSettings* GetRenderActorSettings() const + { + return m_renderActorSettings; + } + /** * Set the path of the media root directory. * @param path The path of the media root folder. @@ -347,6 +360,8 @@ namespace EMotionFX Recorder* m_recorder; /**< The recorder. */ MotionInstancePool* m_motionInstancePool; /**< The motion instance pool. */ DebugDraw* m_debugDraw; /**< The debug drawing system. */ + AZ::Render::RenderActorSettings* m_renderActorSettings; /**< The global render actor settings. */ + AZStd::vector m_threadDatas; /**< The per thread data. */ MCore::Distance::EUnitType m_unitType; /**< The unit type, on default it is MCore::Distance::UNITTYPE_METERS. */ float m_globalSimulationSpeed; /**< The global simulation speed, default is 1.0. */ @@ -412,6 +427,12 @@ namespace EMotionFX */ void SetDebugDraw(DebugDraw* draw); + /** + * Set the render actor settings. + * @param settings The render actor settings. + */ + void SetRenderActorSettings(AZ::Render::RenderActorSettings* settings); + /** * Set the motion instance pool. * @param pool The motion instance pool. @@ -505,4 +526,5 @@ namespace EMotionFX MCORE_INLINE Recorder& GetRecorder() { return *GetEMotionFX().GetRecorder(); } /**< Get the recorder. */ MCORE_INLINE MotionInstancePool& GetMotionInstancePool() { return *GetEMotionFX().GetMotionInstancePool(); } /**< Get the motion instance pool. */ MCORE_INLINE DebugDraw& GetDebugDraw() { return *GetEMotionFX().GetDebugDraw(); } /**< Get the debug drawing. */ + MCORE_INLINE AZ::Render::RenderActorSettings& GetRenderActorSettings() { return *GetEMotionFX().GetRenderActorSettings(); }/**< Get the render actor settings. */ } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp index af2cb2c8e8..46c3703949 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp @@ -12,9 +12,7 @@ #include #include #include -#include -#include -#include +#include #include #include @@ -318,6 +316,9 @@ namespace EMStudio options.m_manipulatorMode = static_cast(settings->value("manipulatorMode", options.m_manipulatorMode).toInt()); + AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); + options.CopyToRenderActorSettings(renderActorSettings); + return options; } @@ -1057,6 +1058,23 @@ namespace EMStudio return m_manipulatorMode; } + void RenderOptions::CopyToRenderActorSettings(AZ::Render::RenderActorSettings& settings) const + { + settings.m_vertexNormalsScale = m_vertexNormalsScale; + settings.m_faceNormalsScale = m_faceNormalsScale; + settings.m_tangentsScale = m_tangentsScale; + + settings.m_vertexNormalsColor = m_vertexNormalsColor; + settings.m_faceNormalsColor = m_faceNormalsColor; + settings.m_tangentsColor = m_tangentsColor; + settings.m_mirroredBitangentsColor = m_mirroredBitangentsColor; + settings.m_bitangentsColor = m_bitangentsColor; + settings.m_wireframeColor = m_wireframeColor; + settings.m_staticAABBColor = m_staticAABBColor; + settings.m_skeletonColor = m_skeletonColor; + settings.m_lineSkeletonColor = m_lineSkeletonColor; + } + void RenderOptions::OnGridUnitSizeChangedCallback() const { PluginOptionsNotificationsBus::Event(s_gridUnitSizeOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_gridUnitSizeOptionName); diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h index f146f62215..20d521813d 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.h @@ -18,6 +18,11 @@ QT_FORWARD_DECLARE_CLASS(QSettings); +namespace AZ::Render +{ + class RenderActorSettings; +} + namespace EMStudio { class EMSTUDIO_API RenderOptions @@ -314,6 +319,9 @@ namespace EMStudio void OnLastUsedLayoutChangedCallback() const; void OnRenderSelectionBoxChangedCallback() const; + // Copy render actor related settings to the global settings in emfx. + void CopyToRenderActorSettings(AZ::Render::RenderActorSettings& settings) const; + // Maintain the order between here and the reflect method. // The order in the SerializeContext defines the order it is shown in the UI float m_gridUnitSize; diff --git a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h new file mode 100644 index 0000000000..a23860bcb8 --- /dev/null +++ b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h @@ -0,0 +1,34 @@ +/* + * 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 + +#include + +namespace AZ::Render +{ + // RenderActorSettings is a subset of RenderOptions. The goal is eventually move those actor render related settings out of render options since + // it will be shared between main editor and animation editor. + class RenderActorSettings + { + public: + float m_vertexNormalsScale = 1.0f; + float m_faceNormalsScale = 1.0f; + float m_tangentsScale = 1.0f; + float m_wireframeScale = 1.0f; + + AZ::Color m_vertexNormalsColor{ 0.0f, 1.0f, 0.0f, 1.0f }; + AZ::Color m_faceNormalsColor{ 0.5f, 0.5f, 1.0f, 1.0f }; + AZ::Color m_tangentsColor{ 1.0f, 0.0f, 0.0f, 1.0f }; + AZ::Color m_mirroredBitangentsColor{ 1.0f, 1.0f, 0.0f, 1.0f }; + AZ::Color m_bitangentsColor{ 1.0f, 1.0f, 1.0f, 1.0f }; + AZ::Color m_wireframeColor{ 0.0f, 0.0f, 0.0f, 1.0f }; + AZ::Color m_staticAABBColor{ 0.0f, 0.7f, 0.7f, 1.0f }; + AZ::Color m_lineSkeletonColor{ 0.33333f, 1.0f, 0.0f, 1.0f }; + AZ::Color m_skeletonColor{ 0.19f, 0.58f, 0.19f, 1.0f }; + }; +} // namespace AZ::Render diff --git a/Gems/EMotionFX/Code/emotionfx_shared_files.cmake b/Gems/EMotionFX/Code/emotionfx_shared_files.cmake index b45f15a5be..26b51f280b 100644 --- a/Gems/EMotionFX/Code/emotionfx_shared_files.cmake +++ b/Gems/EMotionFX/Code/emotionfx_shared_files.cmake @@ -42,4 +42,5 @@ set(FILES Source/Integration/Rendering/RenderActorInstance.cpp Source/Integration/Rendering/RenderBackendManager.h Source/Integration/Rendering/RenderBackendManager.cpp + Source/Integration/Rendering/RenderActorSettings.h ) From 68cb8792f7b8f4d9f90416f6d063e52912aecec0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 15:12:27 -0500 Subject: [PATCH 112/200] fix header comments Signed-off-by: Guthrie Adams --- .../Source/Material/EditorMaterialComponentSerializer.cpp | 4 ++-- .../Code/Source/Material/EditorMaterialComponentSerializer.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp index 955fd7a97f..8ae6e44a93 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of - * this distribution. + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h index 6689d11e84..2b6401c67f 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentSerializer.h @@ -1,6 +1,6 @@ /* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of - * this distribution. + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * From cf767fd4bd038e39512a0f193dfd7cb536a9700f Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Mon, 1 Nov 2021 09:33:38 +0000 Subject: [PATCH 113/200] Fix for 'focus' text appearing incorrectly (#5133) Signed-off-by: hultonha --- .../AzToolsFramework/ViewportSelection/InvalidClicks.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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). From d3ff91f15346328e82e4e4fb293256ff3b026b1c Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Mon, 1 Nov 2021 13:16:00 +0100 Subject: [PATCH 114/200] Fixed memory leak of the in the AssetBrowserComponent (#5132) Signed-off-by: igarri --- .../AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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(); } From db01d8dddae6bc7aebcb9b8a091dbea557f9619d Mon Sep 17 00:00:00 2001 From: Santi Paprika <44426596+santipaprika@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:47:45 +0000 Subject: [PATCH 115/200] Fix bug timestamp view 'Once per Second' option (#5080) Signed-off-by: Santi Paprika --- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h | 2 +- Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h index 1bed2b5715..7413390357 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h @@ -249,7 +249,7 @@ namespace AZ // Controls how often the timestamp data is refreshed RefreshType m_refreshType = RefreshType::Realtime; - AZStd::sys_time_t m_lastUpdateTimeMicroSecond; + AZStd::sys_time_t m_lastUpdateTimeMicroSecond = 0; }; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl index 80dcace2df..405848aa35 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl @@ -651,7 +651,7 @@ namespace AZ if (m_refreshType == RefreshType::OncePerSecond) { auto now = AZStd::GetTimeNowMicroSecond(); - if (m_lastUpdateTimeMicroSecond == 0 || now - m_lastUpdateTimeMicroSecond > 1000000) + if (now - m_lastUpdateTimeMicroSecond > 1000000) { needEnable = true; m_lastUpdateTimeMicroSecond = now; From 2dff26ddb56e5073bafebf451cbe2de1be336cd7 Mon Sep 17 00:00:00 2001 From: Artur K <96597+nemerle@users.noreply.github.com> Date: Mon, 1 Nov 2021 15:51:15 +0100 Subject: [PATCH 116/200] Fix asset type retrieval in AssetCatalogModel::GetAssetType (#4995) * Fix asset type retrieval in AssetCatalogModel::GetAssetType Previous logic would visit the next entry in m_extensionToAssetType map, if the previous entry had multiple types was only exiting the inner loop. The main change is that now the first found matching asset type is returned. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Apply reviewer's suggestions + reduce allocations. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- .../UI/AssetCatalogModel.cpp | 62 +++++++++---------- .../UI/AssetCatalogModel.h | 2 +- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp index d0091f968e..df8d6db4a8 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp @@ -197,48 +197,46 @@ AssetCatalogModel::~AssetCatalogModel() AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); } -AZ::Data::AssetType AssetCatalogModel::GetAssetType(QString filename) const +AZ::Data::AssetType AssetCatalogModel::GetAssetType(const QString &filename) const { - AZ::Data::AssetType returnType = AZ::Uuid::CreateNull(); // Compare file extensions with the map created from the asset database. int dotIndex = filename.lastIndexOf('.'); - if (dotIndex >= 0) + if (dotIndex < 0) { - QString extension = filename.mid(dotIndex); - for (auto pair : m_extensionToAssetType) + return AZ::Uuid::CreateNull(); + } + + QStringRef extension = filename.midRef(dotIndex); + for (const auto& pair : m_extensionToAssetType) + { + QString qExtensions = pair.first.c_str(); + if (qExtensions.indexOf(extension) < 0 || pair.second.empty()) { - QString qExtensions = pair.first.c_str(); - if (qExtensions.indexOf(extension) >= 0) - { - if (pair.second.size() > 1) - { - // There are multiple types with this extension. Check each handler to see if they can handle this data type. - AZStd::string azFilename = filename.toStdString().c_str(); - EBUS_EVENT(AzFramework::ApplicationRequests::Bus, MakePathAssetRootRelative, azFilename); - AZ::Data::AssetId assetId; - EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, azFilename.c_str(), AZ::Data::s_invalidAssetType, false); + continue; + } + if (pair.second.size() == 1) + { + return pair.second[0]; + } - for (AZ::Uuid type : pair.second) - { - const AZ::Data::AssetHandler* handler = AZ::Data::AssetManager::Instance().GetHandler(type); - if (handler && handler->CanHandleAsset(assetId)) - { - returnType = type; - break; - } - } - } - else - { - returnType = pair.second[0]; - break; - } + // There are multiple types with this extension. Search for a handler that can handle this data type. + AZStd::string azFilename = filename.toStdString().c_str(); + EBUS_EVENT(AzFramework::ApplicationRequests::Bus, MakePathAssetRootRelative, azFilename); + AZ::Data::AssetId assetId; + EBUS_EVENT_RESULT(assetId, AZ::Data::AssetCatalogRequestBus, GetAssetIdByPath, azFilename.c_str(), AZ::Data::s_invalidAssetType, false); + + for (const AZ::Uuid& type : pair.second) + { + const AZ::Data::AssetHandler* handler = AZ::Data::AssetManager::Instance().GetHandler(type); + if (handler && handler->CanHandleAsset(assetId)) + { + return type; } } } - return returnType; + return AZ::Uuid::CreateNull(); } QStandardItem* AssetCatalogModel::GetPath(QString& path, bool createIfNeeded, QStandardItem* parent) @@ -419,7 +417,7 @@ AssetCatalogEntry* AssetCatalogModel::AddAsset(QString assetPath, AZ::Data::Asse // icons' memory being reclaimed and crashing the Editor. QSize size = fileIcon.actualSize(QSize(16, 16)); QIcon deepCopy = fileIcon.pixmap(size).copy(0, 0, size.width(), size.height()); - + if (!fileIcon.isNull()) { m_assetTypeToIcon[assetType] = deepCopy; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h index c9143bb259..1dffa81d67 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.h @@ -110,7 +110,7 @@ protected: void SetFilterRegExp(const AZStd::string& filterType, const QRegExp& regExp); void ClearFilterRegExp(const AZStd::string& filterType = AZStd::string()); - AZ::Data::AssetType GetAssetType(QString filename) const; + AZ::Data::AssetType GetAssetType(const QString &filename) const; QStandardItem* GetPath(QString& path, bool createIfNeeded, QStandardItem* parent = nullptr); void ApplyFilter(QStandardItem* parent); From 43563060bc44689f4bee16aad315d276eee1bb95 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 08:44:22 -0700 Subject: [PATCH 117/200] Making trait variable consistent and fixing warning (#5118) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Gems/PhysX/Code/CMakeLists.txt | 4 ++-- Gems/PhysX/Code/Source/Utils.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/PhysX/Code/CMakeLists.txt b/Gems/PhysX/Code/CMakeLists.txt index c59db45aa7..bb3d7c08a2 100644 --- a/Gems/PhysX/Code/CMakeLists.txt +++ b/Gems/PhysX/Code/CMakeLists.txt @@ -11,7 +11,7 @@ add_subdirectory(NumericalMethods) ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME}) include(${pal_source_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # for PAL_TRAIT_PHYSX_SUPPORTED -set(PHYSX_ENABLE_RUNNING_BENCHMARKS OFF CACHE BOOL "Adds a target to allow running of the physx benchmarks.") +set(LY_PHYSX_ENABLE_RUNNING_BENCHMARKS OFF CACHE BOOL "Adds a target to allow running of the physx benchmarks.") if(PAL_TRAIT_PHYSX_SUPPORTED) set(physx_dependency 3rdParty::PhysX) @@ -197,7 +197,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) # Only add the physx benchmarks if this flag is set. The benchmark code is still built, as it is part of the PhysX.Tests project. # Currently jenkins has a 1500sec(25min) timeout, our benchmarks can sometimes take over 1500sec and cause a build failure for timeout. # Jenkins currently doesn't upload the results of the benchmarks, so this is ok. - if(PHYSX_ENABLE_RUNNING_BENCHMARKS) + if(LY_PHYSX_ENABLE_RUNNING_BENCHMARKS) ly_add_googlebenchmark( NAME Gem::PhysX.Benchmarks TARGET Gem::PhysX.Tests diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index 3e77ef257a..fecea57d9c 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -102,7 +102,7 @@ namespace PhysX const float scaleFactor = (maxHeightBounds <= minHeightBounds) ? 1.0f : AZStd::numeric_limits::max() / halfBounds; const float heightScale{ 1.0f / scaleFactor }; - [[maybe_unused]] const uint8_t physxMaximumMaterialIndex = 0x7f; + [[maybe_unused]] constexpr uint8_t physxMaximumMaterialIndex = 0x7f; // Delete the cached heightfield object if it is there, and create a new one and save in the shape configuration heightfieldConfig.SetCachedNativeHeightfield(nullptr); From 8e420dad3d4efdc2c20fe4b893b2a2a3cd357567 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 08:46:26 -0700 Subject: [PATCH 118/200] Removes some usage of DEDICATED_SERVER (#5119) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Legacy/CrySystem/CrySystem_precompiled.h | 7 ------- .../World/UiCanvasAssetRefComponent.cpp | 19 ++++++++++--------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Code/Legacy/CrySystem/CrySystem_precompiled.h b/Code/Legacy/CrySystem/CrySystem_precompiled.h index faa924931f..3ececa6514 100644 --- a/Code/Legacy/CrySystem/CrySystem_precompiled.h +++ b/Code/Legacy/CrySystem/CrySystem_precompiled.h @@ -60,13 +60,6 @@ #include -#if defined(WIN32) || defined(WIN64) || defined(APPLE) || defined(LINUX) -#if defined(DEDICATED_SERVER) -// enable/disable map load slicing functionality from the build -#define MAP_LOADING_SLICING -#endif -#endif - #ifdef WIN32 #include #include diff --git a/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp b/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp index d2a307ecaf..59d764f297 100644 --- a/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp +++ b/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp @@ -239,15 +239,16 @@ void UiCanvasAssetRefComponent::Activate() //////////////////////////////////////////////////////////////////////////////////////////////////// void UiCanvasAssetRefComponent::Deactivate() { -#if !defined(DEDICATED_SERVER) - if (m_canvasEntityId.IsValid()) + if (!gEnv->IsDedicated()) { - gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); - m_canvasEntityId.SetInvalid(); - } + if (m_canvasEntityId.IsValid()) + { + gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); + m_canvasEntityId.SetInvalid(); + } - UiCanvasAssetRefBus::Handler::BusDisconnect(); - UiCanvasRefBus::Handler::BusDisconnect(); - UiCanvasManagerNotificationBus::Handler::BusDisconnect(); -#endif + UiCanvasAssetRefBus::Handler::BusDisconnect(); + UiCanvasRefBus::Handler::BusDisconnect(); + UiCanvasManagerNotificationBus::Handler::BusDisconnect(); + } } From 7ba7928559a9b6172e618b2a80e68a5c699beca7 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 1 Nov 2021 11:19:08 -0500 Subject: [PATCH 119/200] Removing redundant registration of script assets Signed-off-by: Guthrie Adams --- .../AzCore/AzCore/Script/ScriptSystemComponent.cpp | 2 ++ .../Common/Code/Source/EditorCommonSystemComponent.cpp | 8 -------- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 3 --- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp index a83232c8cb..d34f43e433 100644 --- a/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Script/ScriptSystemComponent.cpp @@ -87,6 +87,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()) { 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 @@ -101,13 +100,6 @@ namespace AZ materialFunctorRegistration->RegisterMaterialFunctor("ConvertEmissiveUnit", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("HandleSubsurfaceScatteringParameters", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("Lua", azrtti_typeid()); - - // Add asset types and extensions to AssetCatalog. Uses "AssetCatalogService". - auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); - if (assetCatalog) - { - assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); - } } void EditorCommonSystemComponent::Deactivate() diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index a5884ccce9..e509890efa 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -61,7 +61,6 @@ // Asset types #include -#include #include #include #include @@ -357,7 +356,6 @@ namespace LmbrCentral auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); if (assetCatalog) { - assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); @@ -371,7 +369,6 @@ namespace LmbrCentral assetCatalog->AddExtension("xml"); assetCatalog->AddExtension("mtl"); assetCatalog->AddExtension("dccmtl"); - assetCatalog->AddExtension("lua"); assetCatalog->AddExtension("sprite"); assetCatalog->AddExtension("cax"); } From 7ac69c51db3a2dd27901d913ed41d92f4e532438 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 1 Nov 2021 11:49:19 -0500 Subject: [PATCH 120/200] Added .gitignore for __pycache__ and pyc files to the python tool gemplate. Signed-off-by: Chris Galvan --- Templates/PythonToolGem/Template/.gitignore | 2 ++ Templates/PythonToolGem/template.json | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 Templates/PythonToolGem/Template/.gitignore diff --git a/Templates/PythonToolGem/Template/.gitignore b/Templates/PythonToolGem/Template/.gitignore new file mode 100644 index 0000000000..7a60b85e14 --- /dev/null +++ b/Templates/PythonToolGem/Template/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/Templates/PythonToolGem/template.json b/Templates/PythonToolGem/template.json index 9f4aded036..6dc68de3fc 100644 --- a/Templates/PythonToolGem/template.json +++ b/Templates/PythonToolGem/template.json @@ -12,6 +12,12 @@ ], "icon_path": "preview.png", "copyFiles": [ + { + "file": ".gitignore", + "origin": ".gitignore", + "isTemplated": false, + "isOptional": false + }, { "file": "CMakeLists.txt", "origin": "CMakeLists.txt", From 9886603f99295a97250ecdde203d216a5115e4e1 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 26 Oct 2021 02:29:12 -0700 Subject: [PATCH 121/200] Bug Fix: resolve entity ordering for EntityOutliner (#4798) (#4938) * bugifx: resolve dragging behaviour for EntityOutliner (#4798) Signed-off-by: Michael Pollind * chore: cleanup and rework logic Signed-off-by: Michael Pollind --- .../UI/Outliner/EntityOutlinerListModel.cpp | 50 ++++++++++++------- .../UI/Outliner/EntityOutlinerListModel.hxx | 9 +++- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp index a5f1e29942..434a1d8303 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp @@ -943,13 +943,15 @@ namespace AzToolsFramework { return false; } - + + const int count = rowCount(parent); AZ::EntityId newParentId = GetEntityFromIndex(parent); - AZ::EntityId beforeEntityId = GetEntityFromIndex(index(row, 0, parent)); + AZ::EntityId beforeEntityId = (row >= 0 && row < count) ? GetEntityFromIndex(index(row, 0, parent)) : AZ::EntityId(); EntityIdList topLevelEntityIds; topLevelEntityIds.reserve(entityIdListContainer.m_entityIds.size()); ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::FindTopLevelEntityIdsInactive, entityIdListContainer.m_entityIds, topLevelEntityIds); - if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId)) + const auto appendActionForInvalid = newParentId.IsValid() && (row >= count) ? AppendEnd : AppendBeginning; + if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId, appendActionForInvalid)) { return false; } @@ -1046,7 +1048,7 @@ namespace AzToolsFramework return true; } - bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId) + bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId, ReparentForInvalid forInvalid) { AZ_PROFILE_FUNCTION(AzToolsFramework); if (!CanReparentEntities(newParentId, selectedEntityIds)) @@ -1056,10 +1058,18 @@ namespace AzToolsFramework m_isFilterDirty = true; - ScopedUndoBatch undo("Reparent Entities"); //capture child entity order before re-parent operation, which will automatically add order info if not present EntityOrderArray entityOrderArray = GetEntityChildOrder(newParentId); + //search for the insertion entity in the order array + const auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId); + const bool hasInvalidIndex = beforeEntityItr == entityOrderArray.end(); + if (hasInvalidIndex && forInvalid == None) + { + return false; + } + + ScopedUndoBatch undo("Reparent Entities"); // The new parent is dirty due to sort change(s) undo.MarkEntityDirty(GetEntityIdForSortInfo(newParentId)); @@ -1088,9 +1098,7 @@ namespace AzToolsFramework } } - //search for the insertion entity in the order array - auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId); - + //replace order info matching selection with bad values rather than remove to preserve layout for (auto& id : entityOrderArray) { @@ -1100,17 +1108,25 @@ namespace AzToolsFramework } } - if (newParentId.IsValid()) + //if adding to a valid parent entity, insert at the found entity location or at the head/tail depending on placeAtTail flag + if (hasInvalidIndex) { - //if adding to a valid parent entity, insert at the found entity location or at the head of the container - auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.begin(); - entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end()); - } - else + switch(forInvalid) + { + case AppendEnd: + entityOrderArray.insert(entityOrderArray.end(), processedEntityIds.begin(), processedEntityIds.end()); + break; + case AppendBeginning: + entityOrderArray.insert(entityOrderArray.begin(), processedEntityIds.begin(), processedEntityIds.end()); + break; + default: + AZ_Assert(false, "Unexpected type for ReparentForInvalid"); + break; + } + } + else { - //if adding to an invalid parent entity (the root), insert at the found entity location or at the tail of the container - auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.end(); - entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end()); + entityOrderArray.insert(beforeEntityItr, processedEntityIds.begin(), processedEntityIds.end()); } //remove placeholder entity ids diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx index 8176867038..0a46ee4850 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx @@ -72,6 +72,13 @@ namespace AzToolsFramework ColumnCount //!< Total number of columns }; + enum ReparentForInvalid + { + None, //!< For an invalid location the entity does not change location + AppendEnd, //!< Append Item to end of target parent list + AppendBeginning, //!< Append Item to the beginning of target parent list + }; + // Note: the ColumnSortIndex column isn't shown, hence the -1 and the need for a separate counter. // A wrong column count number causes refresh issues and hover mismatch on model update. static const int VisibleColumnCount = ColumnCount - 1; @@ -162,7 +169,7 @@ namespace AzToolsFramework // Buffer Processing Slots - These are called using single-shot events when the buffers begin to fill. bool CanReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds) const; - bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId()); + bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId(), ReparentForInvalid forInvalid = None); //! Use the current filter setting and re-evaluate the filter. void InvalidateFilter(); From 2cc4f322b7313feba612572f5fa3297ef270c711 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:06:04 -0700 Subject: [PATCH 122/200] Skips signing when there is no upload URL (#5120) * Skips signing when there is no upload URL so we can run the scripts locally Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Fixes prebuild command and improves post build command to not depend on psiexec Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Platform/Windows/PackagingPostBuild.cmake | 78 +++++++++++-------- .../Platform/Windows/PackagingPreBuild.cmake | 38 ++++++--- 2 files changed, 74 insertions(+), 42 deletions(-) diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake index 377a9fb221..ac457bea87 100644 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ b/cmake/Platform/Windows/PackagingPostBuild.cmake @@ -32,9 +32,6 @@ set(_addtional_defines -dCPACK_RESOURCE_PATH=${CPACK_SOURCE_DIR}/Platform/Windows/Packaging ) -file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) -file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) - if(CPACK_LICENSE_URL) list(APPEND _addtional_defines -dCPACK_LICENSE_URL=${CPACK_LICENSE_URL}) endif() @@ -58,28 +55,41 @@ set(_light_command -o "${_bootstrap_output_file}" ) -set(_signing_command - psexec.exe - -accepteula - -nobanner - -s - powershell.exe - -NoLogo - -ExecutionPolicy Bypass - -File ${_sign_script} -) +if(CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) + file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) + + unset(_signing_command) + find_program(_psiexec_path psexec.exe) + if(_psiexec_path) + list(APPEND _signing_command + ${_psiexec_path} + -accepteula + -nobanner + -s + ) + endif() -message(STATUS "Signing package files in ${_cpack_wix_out_dir}") -execute_process( - COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) + find_program(_powershell_path powershell.exe REQUIRED) + list(APPEND _signing_command + ${_powershell_path} + -NoLogo + -ExecutionPolicy Bypass + -File ${_sign_script} + ) -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") + message(STATUS "Signing package files in ${_cpack_wix_out_dir}") + execute_process( + COMMAND ${_signing_command} -packagePath ${_cpack_wix_out_dir} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE + ) + + if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing package files. ${_signing_errors}") + endif() endif() message(STATUS "Creating Bootstrap Installer...") @@ -107,17 +117,19 @@ file(COPY ${_bootstrap_output_file} message(STATUS "Bootstrap installer generated to ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename}") -message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") -execute_process( - COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} - RESULT_VARIABLE _signing_result - ERROR_VARIABLE _signing_errors - OUTPUT_VARIABLE _signing_output - ECHO_OUTPUT_VARIABLE -) +if(CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + message(STATUS "Signing bootstrap installer in ${CPACK_PACKAGE_DIRECTORY}") + execute_process( + COMMAND ${_signing_command} -bootstrapPath ${CPACK_PACKAGE_DIRECTORY}/${_bootstrap_filename} + RESULT_VARIABLE _signing_result + ERROR_VARIABLE _signing_errors + OUTPUT_VARIABLE _signing_output + ECHO_OUTPUT_VARIABLE + ) -if(NOT ${_signing_result} EQUAL 0) - message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") + if(NOT ${_signing_result} EQUAL 0) + message(FATAL_ERROR "An error occurred during signing bootstrap installer. ${_signing_errors}") + endif() endif() # use the internal default path if somehow not specified from cpack_configure_downloads diff --git a/cmake/Platform/Windows/PackagingPreBuild.cmake b/cmake/Platform/Windows/PackagingPreBuild.cmake index d3924c7a02..7f2eedf352 100644 --- a/cmake/Platform/Windows/PackagingPreBuild.cmake +++ b/cmake/Platform/Windows/PackagingPreBuild.cmake @@ -6,21 +6,41 @@ # # +if(NOT CPACK_UPLOAD_URL) # Skip signing if we are not uploading the package + return() +endif() + file(REAL_PATH "${CPACK_SOURCE_DIR}/.." _root_path) set(_cpack_wix_out_dir ${CPACK_TOPLEVEL_DIRECTORY}) file(TO_NATIVE_PATH "${_root_path}/scripts/signer/Platform/Windows/signer.ps1" _sign_script) -set(_signing_command - psexec.exe - -accepteula - -nobanner - -s - powershell.exe +unset(_signing_command) +find_program(_psiexec_path psexec.exe) +if(_psiexec_path) + list(APPEND _signing_command + ${_psiexec_path} + -accepteula + -nobanner + -s + ) +endif() + +find_program(_powershell_path powershell.exe REQUIRED) +list(APPEND _signing_command + ${_powershell_path} -NoLogo - -ExecutionPolicy Bypass + -ExecutionPolicy Bypass -File ${_sign_script} ) +# This requires to have a valid local certificate. In continuous integration, these certificates are stored +# in the machine directly. +# You can generate a test certificate to be able to run this in a PowerShell elevated promp with: +# New-SelfSignedCertificate -DnsName foo.o3de.com -Type CodeSigning -CertStoreLocation Cert:\CurrentUser\My +# Export-Certificate -Cert (Get-ChildItem Cert:\CurrentUser\My\) -Filepath "c:\selfsigned.crt" +# Import-Certificate -FilePath "c:\selfsigned.crt" -Cert Cert:\CurrentUser\TrustedPublisher +# Import-Certificate -FilePath "c:\selfsigned.crt" -Cert Cert:\CurrentUser\Root + message(STATUS "Signing executable files in ${_cpack_wix_out_dir}") execute_process( COMMAND ${_signing_command} -exePath ${_cpack_wix_out_dir} @@ -32,6 +52,6 @@ execute_process( if(NOT ${_signing_result} EQUAL 0) message(FATAL_ERROR "An error occurred during signing executable files. ${_signing_errors}") +else() + message(STATUS "Signing exes complete!") endif() - -message(STATUS "Signing exes complete!") From edf5e7a242fd2b3b9853f2d24847ab30465c342f Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:06:37 -0700 Subject: [PATCH 123/200] Cleanup of validation script exclusions (#5134) * Validation lists cleanup Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * more cleanup Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../commit_validation/commit_validation.py | 12 ++++-------- .../commit_validation/pal_allowedlist.txt | 3 --- .../validator_data_LEGAL_REVIEW_REQUIRED.py | 14 ++------------ 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/scripts/commit_validation/commit_validation/commit_validation.py b/scripts/commit_validation/commit_validation/commit_validation.py index b9d992fc9c..513244a735 100755 --- a/scripts/commit_validation/commit_validation/commit_validation.py +++ b/scripts/commit_validation/commit_validation/commit_validation.py @@ -173,16 +173,12 @@ EXCLUDED_VALIDATION_PATTERNS = [ '*/3rdParty/*', '*/__pycache__/*', '*/External/*', - 'build', - 'Cache', - '*/Code/Framework/AzCore/azgnmx/azgnmx/*', - 'Code/Tools/CryFXC', - 'Code/Tools/HLSLCrossCompiler', - 'Code/Tools/HLSLCrossCompilerMETAL', - 'Docs', + 'build', # build artifacts + '*/Cache/*', # Asset processing artifacts + 'install', # install layout artifacts 'python/runtime', + 'restricted/*/Code/Framework/AzCore/azgnmx/azgnmx/*', 'restricted/*/Tools/*RemoteControl', - 'Tools/3dsmax', '*/user/Cache/*', '*/user/log/*', ] diff --git a/scripts/commit_validation/commit_validation/pal_allowedlist.txt b/scripts/commit_validation/commit_validation/pal_allowedlist.txt index 4c90bcb6b4..6fd5aab62e 100644 --- a/scripts/commit_validation/commit_validation/pal_allowedlist.txt +++ b/scripts/commit_validation/commit_validation/pal_allowedlist.txt @@ -23,7 +23,6 @@ */Code/Framework/AzCore/AzCore/std/parallel/binary_semaphore.h */Code/Framework/AzCore/AzCore/std/parallel/semaphore.h */Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h -*/Code/Framework/AzCore/Platform/AppleTV/AzCore/AzCore_Traits_AppleTV.h */Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h */Code/Framework/AzCore/Platform/Jasper/AzCore/AzCore_Traits_Jasper.h */Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -49,7 +48,6 @@ */Code/Tools/* */Gems/*/3rdParty/* */Gems/*/External/* -*/Gems/CryLegacy* */Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLInclude.h */Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp */Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/PluginManager.cpp @@ -61,4 +59,3 @@ */Gems/SaveData/Code/Tests/SaveDataTest.cpp */Gems/WhiteBox/Code/Source/Rendering/Legacy/WhiteBoxLegacyRenderMesh.cpp */restricted/*/Code/Framework/AzCore/AzCore/AzCore_Traits_*.h -*/Tools/CryDeprecation/precompile_check_defines.h diff --git a/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py b/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py index 666e04a2b0..0c008cbe65 100755 --- a/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py +++ b/scripts/scrubbing/validator_data_LEGAL_REVIEW_REQUIRED.py @@ -100,14 +100,10 @@ def get_prohibited_platforms_for_package(package): def get_bypassed_directories(is_all): # Temporarily exempt folders to not fail validation while people is fixing validation errors, they will be removed once the errors are fixed. temp_bypass_directories = [ - 'commit_validation', - 'LauncherTestTools', - 'AutomatedTesting', - 'Atom' + 'commit_validation' ] bypassed_directories = [ - 'python', - 'AWSPythonSDK' + 'python' ] if not is_all: bypassed_directories.extend([ @@ -116,13 +112,7 @@ def get_bypassed_directories(is_all): 'Cache', 'logs', 'AssetProcessorTemp', - 'JenkinsScripts', - 'BuildLambdaFunctions', - 'layouts', - '.idea', 'user/log', - 'DirectXShaderCompiler', - 'v-hacd', 'External' ]) bypassed_directories.extend(temp_bypass_directories) From c87670bbfb1d294ff9856781d9da39d897adce42 Mon Sep 17 00:00:00 2001 From: Tommy Walton Date: Mon, 1 Nov 2021 11:38:45 -0700 Subject: [PATCH 124/200] Fix innocuous release build error in RPIUtils LoadStreamingTexture (#5021) Signed-off-by: Tommy Walton --- Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp index e70885daa1..fda8f967da 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp @@ -119,7 +119,12 @@ namespace AZ AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown; AzFramework::AssetSystemRequestBus::BroadcastResult( status, &AzFramework::AssetSystemRequestBus::Events::CompileAssetSync, path); - AZ_Error("RPIUtils", status == AzFramework::AssetSystem::AssetStatus_Compiled, "Could not compile image at '%s'", path.data()); + + // When running with no Asset Processor (for example in release), CompileAssetSync will return AssetStatus_Unknown. + AZ_Error( + "RPIUtils", + status == AzFramework::AssetSystem::AssetStatus_Compiled || status == AzFramework::AssetSystem::AssetStatus_Unknown, + "Could not compile image at '%s'", path.data()); Data::AssetId streamingImageAssetId; Data::AssetCatalogRequestBus::BroadcastResult( From 9057cfbcbf6045752ee21443e5e71f78b71237d7 Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 1 Nov 2021 11:41:44 -0700 Subject: [PATCH 125/200] [profiler_capture_api] fixed release compile error Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Code/Legacy/CrySystem/AZCoreLogSink.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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; From fa32940205d51a91845bd89ce441ea00ad8571b7 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Mon, 1 Nov 2021 13:01:59 -0700 Subject: [PATCH 126/200] Adding logs to dedicated-server start up (unable to use for automated testing just yet since remote console cant be connected that early). Adding pytest check to make sure AutomatedTesting.ServerLauncher is running. Moved sveditor_port to MultiplayerEditorConnection since it was never actually getting used when it was in EditorSystemComponent (dedicated servers dont know about editor) Signed-off-by: Gene Walters --- .../editor_python_test_tools/utils.py | 13 +++-- .../Editor/MultiplayerEditorConnection.cpp | 51 ++++++++++--------- .../Editor/MultiplayerEditorConnection.h | 2 + .../MultiplayerEditorSystemComponent.cpp | 6 +-- 4 files changed, 42 insertions(+), 30 deletions(-) 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 77143a8ae7..481d73274f 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py @@ -16,6 +16,8 @@ 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): @@ -103,15 +105,18 @@ class TestHelper: 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, 1.0) + 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, 30.0) + 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, 30.0) + 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(), 10.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 diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index 2a62e35e3a..3c3c4f0664 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -26,6 +26,7 @@ namespace Multiplayer using namespace AzNetworking; AZ_CVAR(bool, editorsv_isDedicated, false, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether to init as a server expecting data from an Editor. Do not modify unless you're sure of what you're doing."); + AZ_CVAR(uint16_t, editorsv_port, DefaultServerEditorPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that the multiplayer editor gem will bind to for traffic."); MultiplayerEditorConnection::MultiplayerEditorConnection() : m_byteStream(&m_buffer) @@ -33,33 +34,37 @@ namespace Multiplayer m_networkEditorInterface = AZ::Interface::Get()->CreateNetworkInterface( AZ::Name(MpEditorInterfaceName), ProtocolType::Tcp, TrustZone::ExternalClientToServer, *this); m_networkEditorInterface->SetTimeoutMs(AZ::TimeMs{ 0 }); // Disable timeouts on this network interface - if (editorsv_isDedicated) + ActivateDedicatedEditorServer(); + } + + void MultiplayerEditorConnection::ActivateDedicatedEditorServer() const + { + if (m_isActivated || !editorsv_isDedicated) { - uint16_t editorsv_port = DefaultServerEditorPort; - const auto console = AZ::Interface::Get(); - if (console->GetCvarValue("editorsv_port", editorsv_port) != AZ::GetValueResult::Success) - { - AZ_Assert( false, - "MultiplayerEditorConnection failed! Could not find the editorsv_port cvar; we may not be able to connect to the editor's port! Please update this code to use a valid cvar!") - } + return; + } + m_isActivated = true; + + AZ_Assert(m_networkEditorInterface, "MP Editor Network Interface was unregistered before Editor Server could start listening.") - AZ_Assert(m_networkEditorInterface, "MP Editor Network Interface was unregistered before Editor Server could start listening.") + // Check if there's already an Editor out there waiting to connect + const ConnectionId editorServerToEditorConnectionId = + m_networkEditorInterface->Connect(IpAddress(LocalHost.data(), editorsv_port, ProtocolType::Tcp)); - // Check if there's already an Editor out there waiting to connect - const ConnectionId editorServerToEditorConnectionId = m_networkEditorInterface->Connect(IpAddress(LocalHost.data(), editorsv_port, ProtocolType::Tcp)); - - // If there wasn't an Editor waiting for this server to start, then assume this is an editor-server launched by hand... listen and wait for the editor to request a connection - if (editorServerToEditorConnectionId == InvalidConnectionId) - { - m_networkEditorInterface->Listen(editorsv_port); - } - else - { - m_networkEditorInterface->SendReliablePacket(editorServerToEditorConnectionId, MultiplayerEditorPackets::EditorServerReadyForLevelData()); - } + // If there wasn't an Editor waiting for this server to start, then assume this is an editor-server launched by hand... listen + // and wait for the editor to request a connection + if (editorServerToEditorConnectionId == InvalidConnectionId) + { + m_networkEditorInterface->Listen(editorsv_port); + AZ_Printf("MultiplayerEditorConnection", "Editor-server activation did not find an editor in game-mode willing to connect; we'll instead wait and listen for an editor trying to connect to us.") + } + else + { + m_networkEditorInterface->SendReliablePacket(editorServerToEditorConnectionId, MultiplayerEditorPackets::EditorServerReadyForLevelData()); + AZ_Printf("MultiplayerEditorConnection", "Editor-server activation has found and connected to the editor.") } } - + bool MultiplayerEditorConnection::HandleRequest ( [[maybe_unused]] AzNetworking::IConnection* connection, @@ -136,7 +141,7 @@ namespace Multiplayer networkInterface->Listen(sv_port); - AZLOG_INFO("Editor Server completed asset receive, responding to Editor..."); + AZLOG_INFO("Editor Server completed receiving the editor's level assets, responding to Editor..."); return connection->SendReliablePacket(MultiplayerEditorPackets::EditorServerReady()); } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h index 3828d751f0..f6510896fe 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.h @@ -45,9 +45,11 @@ namespace Multiplayer //! @} private: + void ActivateDedicatedEditorServer() const; AzNetworking::INetworkInterface* m_networkEditorInterface = nullptr; AZStd::vector m_buffer; AZ::IO::ByteContainerStream> m_byteStream; + mutable bool m_isActivated = false; }; } diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp index 388e38dee7..11aca101b3 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorSystemComponent.cpp @@ -37,10 +37,10 @@ namespace Multiplayer AZ_CVAR(AZ::CVarFixedString, editorsv_process, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The server executable that should be run. Empty to use the current project's ServerLauncher"); AZ_CVAR(AZ::CVarFixedString, editorsv_serveraddr, AZ::CVarFixedString(LocalHost), nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The address of the server to connect to"); - AZ_CVAR(uint16_t, editorsv_port, DefaultServerEditorPort, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The port that the multiplayer editor gem will bind to for traffic"); AZ_CVAR(AZ::CVarFixedString, editorsv_rhi_override, "", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Override the default rendering hardware interface (rhi) when launching the Editor server. For example, you may be running an Editor using 'dx12', but want to launch a headless server using 'null'. If empty the server will launch using the same rhi as the Editor."); - + AZ_CVAR_EXTERNED(uint16_t, editorsv_port); + ////////////////////////////////////////////////////////////////////////// void PyEnterGameMode() { @@ -298,7 +298,7 @@ namespace Multiplayer "Editor multiplayer game-mode failed! Could not connect to an editor-server. editorsv_launch is false so we're assuming you're running your own editor-server at editorsv_serveraddr(%s) on editorsv_port(%i). " "Either set editorsv_launch=true so the editor launches an editor-server for you, or launch your own editor-server by hand before entering game-mode. Remember editor-servers must use editorsv_isDedicated=true.", remoteAddress.c_str(), - static_cast < uint16_t>(editorsv_port)) + static_cast(editorsv_port)) return; } From 8f56dc10c33ae73acaa99c8690e8bc91a1cec2bc Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Mon, 1 Nov 2021 13:11:34 -0700 Subject: [PATCH 127/200] Perform sse float comparisons with the floating-point intrinsics (#5115) Signed-off-by: Chris Burel --- .../Math/Internal/SimdMathCommon_sse.inl | 20 +++++++++---------- .../AzCore/Math/Internal/SimdMathVec1_sse.inl | 13 ++++++------ .../AzCore/Math/Internal/SimdMathVec2_sse.inl | 11 +++++----- .../AzCore/Math/Internal/SimdMathVec3_sse.inl | 13 ++++++------ .../AzCore/Math/Internal/SimdMathVec4_sse.inl | 13 ++++++------ 5 files changed, 37 insertions(+), 33 deletions(-) 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); } From 916fb413c93f92d3c4aea46dac4d7908b48a10fa Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 1 Nov 2021 16:19:27 -0500 Subject: [PATCH 128/200] Fix Assert Absorber being leaked due to one of the tests setting m_errorAbsorber to nullptr without deleting the object (#5176) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AssetProcessor/native/tests/AssetProcessorTest.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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(); From 8da6bea0733aa43c19937fc8ba46d5ab3e514968 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:26:55 -0700 Subject: [PATCH 129/200] =?UTF-8?q?ATOM-16747=20RPISystemInterface::GetDef?= =?UTF-8?q?aultScene=20returns=20the=20scene=20crea=E2=80=A6=20(#5153)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ATOM-16747 RPISystemInterface::GetDefaultScene returns the scene created by PreviewRenderer but not the Main Scene Deprecate GetDefaultScene() function. Update all the places which use GetDefaultScene to use Scene::GetFeatureProcessorFromEntityId or GetMainScene. Tested with Editor, UI Editor, Material Editor, game launcher. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> --- .../Code/Source/BootstrapSystemComponent.cpp | 1 + .../Code/Source/LuxCore/LuxCoreTexture.cpp | 10 +++++-- .../Code/Include/Atom/RPI.Public/RPISystem.h | 3 +- .../Atom/RPI.Public/RPISystemInterface.h | 12 +++++--- .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 17 +++++++---- .../Atom/RPI.Reflect/System/SceneDescriptor.h | 4 +++ .../RPI/Code/Source/RPI.Public/Culling.cpp | 4 +-- .../RPI/Code/Source/RPI.Public/RPISystem.cpp | 29 +++++++++++++++---- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 25 ++++++++++++++-- .../PreviewRenderer/PreviewRenderer.cpp | 1 + .../MaterialEditorViewportInputController.cpp | 4 +-- .../RotateEnvironmentBehavior.cpp | 3 +- .../Viewport/MaterialViewportRenderer.cpp | 1 + .../Code/Source/AtomBridgeSystemComponent.cpp | 6 ++-- .../AtomDebugDisplayViewportInterface.cpp | 3 +- .../AtomDebugDisplayViewportInterface.h | 2 +- .../AtomLyIntegration/AtomFont/FFont.h | 12 -------- ...eGlobalIlluminationComponentController.cpp | 6 +--- .../Source/Grid/GridComponentController.cpp | 2 +- .../DisplayMapperComponentController.cpp | 3 +- .../SkinnedMesh/SkinnedMeshDebugDisplay.h | 2 +- .../Tools/EMStudio/AnimViewportRenderer.cpp | 4 +-- .../Components/BlastSystemComponent.cpp | 25 +++++++++------- Gems/LyShine/Code/Source/Draw2d.cpp | 12 ++++---- Gems/LyShine/Code/Source/LyShine.cpp | 4 +-- Gems/LyShine/Code/Source/UiRenderer.cpp | 13 +++++---- Gems/LyShine/Code/Source/UiRenderer.h | 4 +-- 27 files changed, 127 insertions(+), 85 deletions(-) diff --git a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index 3f5761270a..ed3241b312 100644 --- a/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp +++ b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp @@ -259,6 +259,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/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp index aa906a06f7..1fd8f0d91c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/LuxCore/LuxCoreTexture.cpp @@ -32,7 +32,7 @@ namespace AZ { if (m_rtPipeline) { - AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->RemoveRenderPipeline(m_rtPipeline->GetId()); + m_rtPipeline->RemoveFromScene(); m_rtPipeline = nullptr; } @@ -111,8 +111,12 @@ namespace AZ parentPass->SetSourceTexture(m_texture, RHI::Format::R8G8B8A8_UNORM); break; } - - AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->AddRenderPipeline(m_rtPipeline); + + const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("RPI")); + if (mainScene) + { + mainScene->AddRenderPipeline(m_rtPipeline); + } } bool LuxCoreTexture::IsIBLTexture() diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h index 4914e4b6fe..92370c5a82 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystem.h @@ -70,7 +70,8 @@ namespace AZ void InitializeSystemAssets() override; void RegisterScene(ScenePtr scene) override; void UnregisterScene(ScenePtr scene) override; - ScenePtr GetScene(const SceneId& sceneId) const override; + Scene* GetScene(const SceneId& sceneId) const override; + Scene* GetSceneByName(const AZ::Name& name) const override; ScenePtr GetDefaultScene() const override; RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) override; Data::Asset GetCommonShaderAssetForSrgs() const override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h index fe81596bd7..3f30d498cf 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPISystemInterface.h @@ -13,6 +13,7 @@ #include +#include #include namespace AZ @@ -46,11 +47,14 @@ namespace AZ //! Unregister a scene from RPISystem. The scene won't be simulated or rendered. virtual void UnregisterScene(ScenePtr scene) = 0; - // [GFX TODO] to be removed when we have scene setup in AZ Core - virtual ScenePtr GetDefaultScene() const = 0; - + //! Deprecated. Use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead + AZ_DEPRECATED(virtual ScenePtr GetDefaultScene() const = 0;, "This method has been deprecated. Please use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead."); + //! Get scene by using scene id. - virtual ScenePtr GetScene(const SceneId& sceneId) const = 0; + virtual Scene* GetScene(const SceneId& sceneId) const = 0; + + //! Get scene by using scene name. + virtual Scene* GetSceneByName(const AZ::Name& name) const = 0; //! Get the render pipeline created for a window virtual RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) = 0; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index fc81368331..f86383101a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -80,6 +80,9 @@ namespace AZ //! Gets the RPI::Scene for a given entityContextId. //! May return nullptr if there is no RPI::Scene created for that entityContext. static Scene* GetSceneForEntityContextId(AzFramework::EntityContextId entityContextId); + + //! Gets the RPI::Scene for a given entityId. + static Scene* GetSceneForEntityId(AZ::EntityId entityId); ~Scene(); @@ -135,6 +138,8 @@ namespace AZ const SceneId& GetId() const; + AZ::Name GetName() const; + //! Set default pipeline by render pipeline ID. //! It returns true if the default render pipeline was set from the input ID. //! If the specified render pipeline doesn't exist in this scene then it won't do anything and returns false. @@ -245,6 +250,9 @@ namespace AZ // The uuid to identify this scene. SceneId m_id; + // Scene's name which is set at initialization. Can be empty + AZ::Name m_name; + bool m_activated = false; bool m_taskGraphActive = false; // update during tick, to ensure it only changes on frame boundaries @@ -286,13 +294,10 @@ namespace AZ template FeatureProcessorType* Scene::GetFeatureProcessorForEntity(AZ::EntityId entityId) { - // Find the entity context for the entity ID. - AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); - AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId); - - if (!entityContextId.IsNull()) + RPI::Scene* renderScene = GetSceneForEntityId(entityId); + if (renderScene) { - return GetFeatureProcessorForEntityContextId(entityContextId); + return renderScene->GetFeatureProcessor(); } return nullptr; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h index 2072568d59..eb7a2b6cb7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/System/SceneDescriptor.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include @@ -25,6 +26,9 @@ namespace AZ //! List of feature processors which the scene will initially enable. AZStd::vector m_featureProcessorNames; + + //! A name used as scene id. It can be used to search a registered scene via RPISystemInterface::GetScene() + AZ::Name m_nameId; }; } // namespace RPI } // namespace AZ diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index 348f0aa57a..ac6b10694e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -699,9 +699,7 @@ namespace AZ m_parentScene = parentScene; AZ_Assert(m_visScene == nullptr, "IVisibilityScene already created for this RPI::Scene"); - char sceneIdBuf[40] = ""; - m_parentScene->GetId().ToString(sceneIdBuf); - AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", sceneIdBuf)); + AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", m_parentScene->GetName().GetCStr())); m_visScene = AZ::Interface::Get()->CreateVisibilityScene(visSceneName); #ifdef AZ_CULL_DEBUG_ENABLED diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp index eb74a81e3e..943966c13b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp @@ -159,6 +159,11 @@ namespace AZ AZ_Assert(false, "Scene was already registered"); return; } + else if (!scene->GetName().IsEmpty() && scene->GetName() == sceneItem->GetName()) + { + // only report a warning if there is a scene with duplicated name + AZ_Warning("RPISystem", false, "There is a registered scene with same name [%s]", scene->GetName().GetCStr()); + } } m_scenes.push_back(scene); @@ -177,28 +182,42 @@ namespace AZ AZ_Assert(false, "Can't unregister scene which wasn't registered"); } - ScenePtr RPISystem::GetScene(const SceneId& sceneId) const + Scene* RPISystem::GetScene(const SceneId& sceneId) const { for (const auto& scene : m_scenes) { if (scene->GetId() == sceneId) { - return scene; + return scene.get(); } } return nullptr; } + Scene* RPISystem::GetSceneByName(const AZ::Name& name) const + { + for (const auto& scene : m_scenes) + { + if (scene->GetName() == name) + { + return scene.get(); + } + } + return nullptr; + } + ScenePtr RPISystem::GetDefaultScene() const { - if (m_scenes.size() > 0) + for (const auto& scene : m_scenes) { - return m_scenes[0]; + if (scene->GetName() == AZ::Name("Main")) + { + return scene; + } } return nullptr; } - RenderPipelinePtr RPISystem::GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) { RenderPipelinePtr renderPipeline; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index c5d82c6f29..41fefda656 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -45,7 +45,9 @@ namespace AZ auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs(); scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName()); } - + + scene->m_name = sceneDescriptor.m_nameId; + return ScenePtr(scene); } @@ -83,10 +85,23 @@ namespace AZ return nullptr; } + Scene* Scene::GetSceneForEntityId(AZ::EntityId entityId) + { + // Find the entity context for the entity ID. + AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull(); + AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId); + + if (!entityContextId.IsNull()) + { + return GetSceneForEntityContextId(entityContextId); + } + return nullptr; + } + Scene::Scene() { - m_id = Uuid::CreateRandom(); + m_id = AZ::Uuid::CreateRandom(); m_cullingScene = aznew CullingScene(); SceneRequestBus::Handler::BusConnect(m_id); m_drawFilterTagRegistry = RHI::DrawFilterTagRegistry::Create(); @@ -299,7 +314,6 @@ namespace AZ // Force to update the lookup table since adding render pipeline would effect any pipeline states created before pass system tick RebuildPipelineStatesLookup(); - AZ_Assert(!m_id.IsNull(), "RPI::Scene needs to have a valid uuid."); SceneNotificationBus::Event(m_id, &SceneNotification::OnRenderPipelineAdded, pipeline); } @@ -785,6 +799,11 @@ namespace AZ { return m_id; } + + AZ::Name Scene::GetName() const + { + return m_name; + } bool Scene::SetDefaultRenderPipeline(const RenderPipelineId& pipelineId) { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp index 2b39a87623..27d468e64b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRenderer.cpp @@ -43,6 +43,7 @@ namespace AtomToolsFramework &PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors); AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("PreviewRenderer"); sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end()); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp index 932e2e7436..1784405ffa 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp @@ -279,9 +279,9 @@ namespace MaterialEditor // reset environment AZ::Transform iblTransform = AZ::Transform::CreateIdentity(); AZ::TransformBus::Event(m_iblEntityId, &AZ::TransformBus::Events::SetLocalTM, iblTransform); + const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + auto skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_iblEntityId); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); if (m_behavior) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp index 21d7dee51b..17fb3f3e52 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/RotateEnvironmentBehavior.cpp @@ -25,8 +25,7 @@ namespace MaterialEditor m_iblEntityId, &MaterialEditorViewportInputControllerRequestBus::Handler::GetIblEntityId); AZ_Assert(m_iblEntityId.IsValid(), "Failed to find m_iblEntityId"); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - m_skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + m_skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_iblEntityId); } void RotateEnvironmentBehavior::TickInternal(float x, float y, float z) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp index 6d6fd377e3..4ad87492e3 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp @@ -67,6 +67,7 @@ namespace MaterialEditor // Create and register a scene with all available feature processors AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("MaterialViewport"); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp index b439ac475c..d822b16486 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomBridgeSystemComponent.cpp @@ -108,7 +108,7 @@ namespace AZ { m_dynamicDrawManager.reset(); AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect(); - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); + RPI::Scene* scene = AZ::RPI::Scene::GetSceneForEntityContextId(m_entityContextId); // Check if scene is emptry since scene might be released already when running AtomSampleViewer if (scene) { @@ -157,9 +157,9 @@ namespace AZ void AtomBridgeSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { - AZ_UNUSED(bootstrapScene); // Make default AtomDebugDisplayViewportInterface - AZStd::shared_ptr mainEntityDebugDisplay = AZStd::make_shared(AzFramework::g_defaultSceneEntityDebugDisplayId); + AZStd::shared_ptr mainEntityDebugDisplay = + AZStd::make_shared(AzFramework::g_defaultSceneEntityDebugDisplayId, bootstrapScene); m_activeViewportsList[AzFramework::g_defaultSceneEntityDebugDisplayId] = mainEntityDebugDisplay; } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index 39d8933863..14f1c5aa0d 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -256,12 +256,11 @@ namespace AZ::AtomBridge viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler); } - AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress) + AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene) { ResetRenderState(); m_viewportId = defaultInstanceAddress; m_defaultInstance = true; - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); InitInternal(scene, nullptr); } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h index 07f4efdf50..5f902c5884 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h @@ -124,7 +124,7 @@ namespace AZ::AtomBridge AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler); explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr); - explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress); + explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene); ~AtomDebugDisplayViewportInterface(); void ResetRenderState(); diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h index 2cc8a67cfa..ff6ad7c151 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h @@ -133,18 +133,6 @@ namespace AZ typedef std::vector FontEffects; typedef FontEffects::iterator FontEffectsIterator; - struct FontPipelineStateMapKey - { - AZ::RPI::SceneId m_sceneId; // which scene pipeline state is attached to (via Render Pipeline) - AZ::RHI::DrawListTag m_drawListTag; // which render pass this pipeline draws in by default - - bool operator<(const FontPipelineStateMapKey& other) const - { - return m_sceneId < other.m_sceneId - || (m_sceneId == other.m_sceneId && m_drawListTag < other.m_drawListTag); - } - }; - struct FontShaderData { AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture"; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp index ee322c8afd..e844219811 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseGlobalIlluminationComponentController.cpp @@ -48,11 +48,7 @@ namespace AZ void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId) { - AZ_UNUSED(entityId); - - const RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - m_featureProcessor = scene->GetFeatureProcessor(); - + m_featureProcessor = AZ::RPI::Scene::GetFeatureProcessorForEntity(entityId); OnConfigChanged(); } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp index b4131894f4..2611021359 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Grid/GridComponentController.cpp @@ -79,7 +79,7 @@ namespace AZ m_entityId = entityId; m_dirty = true; - RPI::ScenePtr scene = RPI::RPISystemInterface::Get()->GetDefaultScene(); + RPI::Scene* scene = RPI::Scene::GetSceneForEntityId(m_entityId); if (scene) { AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId()); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp index e86c909121..a0577c6240 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/PostProcess/DisplayMapper/DisplayMapperComponentController.cpp @@ -357,8 +357,7 @@ namespace AZ void DisplayMapperComponentController::OnConfigChanged() { // Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene. - const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - DisplayMapperFeatureProcessorInterface* fp = scene->GetFeatureProcessor(); + DisplayMapperFeatureProcessorInterface* fp = AZ::RPI::Scene::GetFeatureProcessorForEntity(m_entityId); DisplayMapperConfigurationDescriptor desc; desc.m_operationType = m_configuration.m_displayMapperOperation; desc.m_ldrGradingLutEnabled = m_configuration.m_ldrColorGradingLutEnabled; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h index e789b6dc80..5b060198dc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/SkinnedMesh/SkinnedMeshDebugDisplay.h @@ -48,7 +48,7 @@ namespace AZ // CVar for toggling the display of the scene stats int r_skinnedMeshDisplaySceneStats = 0; // SceneId to query for the stats - RPI::SceneId m_sceneId = RPI::SceneId::CreateNull(); + RPI::SceneId m_sceneId; }; }// namespace Render }// namespace AZ diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index facf7a7b12..1d62e61b0a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -60,6 +60,7 @@ namespace EMStudio // Create and register a scene with all available feature processors AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("AnimViewport"); m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); m_scene->EnableAllFeatureProcessors(); @@ -227,8 +228,7 @@ namespace EMStudio AZ::TransformBus::Event(m_iblEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, iblTransform); const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity(); - AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); + auto skyBoxFeatureProcessorInterface = m_scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); } diff --git a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp index 00629eb65d..4c0f15463a 100644 --- a/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp +++ b/Gems/Blast/Code/Source/Components/BlastSystemComponent.cpp @@ -255,19 +255,22 @@ namespace Blast BlastFamilyComponentRequestBus::Broadcast( &BlastFamilyComponentRequests::FillDebugRenderBuffer, buffer, m_debugRenderMode); - // This is a system component, and thus is not associated with a specific scene, so use the default scene + // This is a system component, and thus is not associated with a specific scene, so use the bootstrap scene // for the debug drawing - const auto defaultScene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); - auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(defaultScene); - - for (DebugLine& line : buffer.m_lines) + const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("Main")); + if (mainScene) { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments; - drawArguments.m_verts = &line.m_p0; - drawArguments.m_vertCount = 2; - drawArguments.m_colors = &line.m_color; - drawArguments.m_colorCount = 1; - drawQueue->DrawLines(drawArguments); + auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(mainScene); + + for (DebugLine& line : buffer.m_lines) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments; + drawArguments.m_verts = &line.m_p0; + drawArguments.m_vertCount = 2; + drawArguments.m_colors = &line.m_color; + drawArguments.m_colorCount = 1; + drawQueue->DrawLines(drawArguments); + } } } } diff --git a/Gems/LyShine/Code/Source/Draw2d.cpp b/Gems/LyShine/Code/Source/Draw2d.cpp index b0539900e2..3476c530b2 100644 --- a/Gems/LyShine/Code/Source/Draw2d.cpp +++ b/Gems/LyShine/Code/Source/Draw2d.cpp @@ -65,7 +65,7 @@ CDraw2d::~CDraw2d() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void CDraw2d::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // At this point the RPI is ready for use @@ -74,16 +74,16 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc AZ::Data::Instance shader = AZ::RPI::LoadCriticalShader(shaderFilepath); // Set scene to be associated with the dynamic draw context - AZ::RPI::ScenePtr scene; + AZ::RPI::Scene* scene = nullptr; if (m_viewportContext) { // Use scene associated with the specified viewport context - scene = m_viewportContext->GetRenderScene(); + scene = m_viewportContext->GetRenderScene().get(); } else { - // No viewport context specified, use default scene - scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + // No viewport context specified, use main scene + scene = bootstrapScene; } AZ_Assert(scene != nullptr, "Attempting to create a DynamicDrawContext for a viewport context that has not been associated with a scene yet."); @@ -113,7 +113,7 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc else { // Render target support is disabled - m_dynamicDraw->SetOutputScope(scene.get()); + m_dynamicDraw->SetOutputScope(scene); } m_dynamicDraw->EndInit(); diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index 2cee4e92eb..19c6e4281e 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -653,12 +653,12 @@ void CLyShine::OnRenderTick() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void CLyShine::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // Load cursor if its path was set before RPI was initialized LoadUiCursor(); - LyShinePassDataRequestBus::Handler::BusConnect(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->GetId()); + LyShinePassDataRequestBus::Handler::BusConnect(bootstrapScene->GetId()); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Gems/LyShine/Code/Source/UiRenderer.cpp b/Gems/LyShine/Code/Source/UiRenderer.cpp index 3111f31615..98b376ec8b 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.cpp +++ b/Gems/LyShine/Code/Source/UiRenderer.cpp @@ -52,7 +52,7 @@ bool UiRenderer::IsReady() return m_isRPIReady; } -void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) +void UiRenderer::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) { // At this point the RPI is ready for use @@ -64,16 +64,17 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra if (m_viewportContext) { // Create a new scene based on the user specified viewport context - m_scene = CreateScene(m_viewportContext); + m_ownedScene = CreateScene(m_viewportContext); + m_scene = m_ownedScene.get(); } else { // No viewport context specified, use default scene - m_scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); + m_scene = bootstrapScene; } // Create a dynamic draw context for UI Canvas drawing for the scene - m_dynamicDraw = CreateDynamicDrawContext(m_scene, uiShader); + m_dynamicDraw = CreateDynamicDrawContext(uiShader); if (m_dynamicDraw) { @@ -93,6 +94,7 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptrEnableAllFeatureProcessors(); // LYSHINE_ATOM_TODO - have a UI pipeline and enable only needed fps @@ -116,7 +118,6 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr UiRenderer::CreateDynamicDrawContext( - AZ::RPI::ScenePtr scene, AZ::Data::Instance uiShader) { // Find the pass that renders the UI canvases after the rtt passes @@ -144,7 +145,7 @@ AZ::RHI::Ptr UiRenderer::CreateDynamicDrawContext( else { // Render target support is disabled - dynamicDraw->SetOutputScope(m_scene.get()); + dynamicDraw->SetOutputScope(m_scene); } dynamicDraw->EndInit(); diff --git a/Gems/LyShine/Code/Source/UiRenderer.h b/Gems/LyShine/Code/Source/UiRenderer.h index 3be3c832d3..0e15d41907 100644 --- a/Gems/LyShine/Code/Source/UiRenderer.h +++ b/Gems/LyShine/Code/Source/UiRenderer.h @@ -152,7 +152,6 @@ private: // member functions //! Create a dynamic draw context for this renderer AZ::RHI::Ptr CreateDynamicDrawContext( - AZ::RPI::ScenePtr scene, AZ::Data::Instance uiShader); //! Bind the global white texture for all the texture units we use @@ -175,7 +174,8 @@ protected: // attributes // Set by user when viewport context is not the main/default viewport AZStd::shared_ptr m_viewportContext; - AZ::RPI::ScenePtr m_scene; + AZ::RPI::ScenePtr m_ownedScene; + AZ::RPI::Scene* m_scene = nullptr; #ifndef _RELEASE int m_debugTextureDataRecordLevel = 0; From 6862b52069821a6ecfb422d2c9a3fa3d621ead44 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:27:22 -0700 Subject: [PATCH 130/200] Convert several physics automated tests with Base test level file converted to prefab file (#5138) * Convert some physics automated tests to use prefab system Signed-off-by: chiyteng * revert changes Signed-off-by: chiyteng * Fix file names Signed-off-by: chiyteng --- .../Physics/TestSuite_Main_Optimized.py | 30 +++++++---- .../PythonTests/Physics/TestSuite_Periodic.py | 21 ++++---- ...ditting.py => Collider_BoxShapeEditing.py} | 6 +-- ...ing.py => Collider_CapsuleShapeEditing.py} | 6 +-- ...ting.py => Collider_SphereShapeEditing.py} | 6 +-- AutomatedTesting/Levels/Base/Base.prefab | 53 +++++++++++++++++++ 6 files changed, 95 insertions(+), 27 deletions(-) rename AutomatedTesting/Gem/PythonTests/Physics/tests/collider/{Collider_BoxShapeEditting.py => Collider_BoxShapeEditing.py} (97%) rename AutomatedTesting/Gem/PythonTests/Physics/tests/collider/{Collider_CapsuleShapeEditting.py => Collider_CapsuleShapeEditing.py} (97%) rename AutomatedTesting/Gem/PythonTests/Physics/tests/collider/{Collider_SphereShapeEditting.py => Collider_SphereShapeEditing.py} (96%) create mode 100644 AutomatedTesting/Levels/Base/Base.prefab 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/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 From 96159c1e3a7614b43e512c22477073e2dde71b14 Mon Sep 17 00:00:00 2001 From: Vincent Liu <5900509+onecent1101@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:52:40 -0700 Subject: [PATCH 131/200] Add missing exclamation mark for documentation (#5144) * Add missing exclamation mark for documentation Signed-off-by: onecent1101 * Add more Signed-off-by: onecent1101 --- .../Matchmaking/IMatchmakingRequests.h | 34 ++++++------- .../Matchmaking/MatchmakingNotifications.h | 10 ++-- .../Matchmaking/MatchmakingRequests.h | 10 ++-- .../Session/ISessionHandlingRequests.h | 44 ++++++++--------- .../AzFramework/Session/ISessionRequests.h | 48 +++++++++---------- .../AzFramework/Session/SessionConfig.h | 28 +++++------ .../Session/SessionNotifications.h | 48 +++++++++---------- .../AzFramework/Session/SessionRequests.h | 28 +++++------ .../AWSGameLiftCreateSessionOnQueueRequest.h | 6 +-- .../Request/AWSGameLiftCreateSessionRequest.h | 8 ++-- .../AWSGameLiftSearchSessionsRequest.h | 6 +-- .../AWSGameLiftStartMatchmakingRequest.h | 5 +- 12 files changed, 138 insertions(+), 137 deletions(-) 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/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 From bf0a309a3c302a44c3e37aa52ae595fa90977267 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Mon, 1 Nov 2021 15:18:30 -0700 Subject: [PATCH 132/200] copy commands need to be per permutation/per configuraiton (#5183) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 18 ++++++++++-------- cmake/Platform/Linux/Install_linux.cmake | 9 ++++++--- cmake/Platform/Mac/Install_mac.cmake | 7 ++++++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 803edb7b1d..2960a99c64 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -525,15 +525,20 @@ function(ly_setup_runtime_dependencies) if(COMMAND ly_setup_runtime_dependencies_copy_function_override) ly_setup_runtime_dependencies_copy_function_override() else() - ly_install(CODE + # despite this copy function being the same, we need to install it per component that uses it + # (which is per-configuration per-permutation component) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "function(ly_copy source_file target_directory) cmake_path(GET source_file FILENAME file_name) if(NOT EXISTS \${target_directory}/\${file_name}) file(COPY \"\${source_file}\" DESTINATION \"\${target_directory}\" FILE_PERMISSIONS ${LY_COPY_PERMISSIONS}) endif() endfunction()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endif() unset(runtime_commands) @@ -574,11 +579,8 @@ endfunction()" list(JOIN runtime_commands " " runtime_commands_str) # the spaces are just to see the right identation in the cmake_install.cmake file foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) string(TOUPPER ${conf} UCONF) - ly_install(CODE -"if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^(${conf})\$\") - ${runtime_commands_str} -endif()" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME}_${UCONF} + ly_install(CODE "${runtime_commands_str}" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} ) endforeach() diff --git a/cmake/Platform/Linux/Install_linux.cmake b/cmake/Platform/Linux/Install_linux.cmake index 54d1e18837..02baa6e61e 100644 --- a/cmake/Platform/Linux/Install_linux.cmake +++ b/cmake/Platform/Linux/Install_linux.cmake @@ -22,9 +22,12 @@ endfunction()]]) function(ly_setup_runtime_dependencies_copy_function_override) string(CONFIGURE "${ly_copy_template}" ly_copy_function_linux @ONLY) - ly_install(CODE "${ly_copy_function_linux}" - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} - ) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(CODE "${ly_copy_function_linux}" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction() include(cmake/Platform/Common/Install_common.cmake) diff --git a/cmake/Platform/Mac/Install_mac.cmake b/cmake/Platform/Mac/Install_mac.cmake index 76c381138d..c75d860c3e 100644 --- a/cmake/Platform/Mac/Install_mac.cmake +++ b/cmake/Platform/Mac/Install_mac.cmake @@ -113,7 +113,12 @@ endfunction() function(ly_setup_runtime_dependencies_copy_function_override) configure_file(${LY_ROOT_FOLDER}/cmake/Platform/Mac/InstallUtils_mac.cmake.in ${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake @ONLY) - ly_install_run_script(${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake) + foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) + string(TOUPPER ${conf} UCONF) + ly_install(SCRIPT "${CMAKE_BINARY_DIR}/runtime_install/InstallUtils_mac.cmake" + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT}_${UCONF} + ) + endforeach() endfunction() From 8b5a0350b57486bbfa04f1233abfd3a086c25ea1 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Mon, 1 Nov 2021 17:27:17 -0500 Subject: [PATCH 133/200] {lyn7621} adding more time via ap_max_activate_time (#5180) * adding more time via ap_max_activate_time so that the Debug version of AP-GUI can load all the builder DLLs Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> --- Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py index 682fcd3560..2019f21004 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py @@ -195,8 +195,11 @@ class AssetProcessor(object): logger.debug("Failed to read port from file", exc_info=ex) return False + # the timeout needs to be large enough to load all the dynamic libraries the AP-GUI loads since the control port + # is opened after all the DLL loads, this can take a long time in a Debug build + ap_max_activate_time = 60 err = AssetProcessorError(f"Failed to read port type {port_type} from {self._workspace.paths.ap_gui_log()}") - waiter.wait_for(_get_port_from_log, timeout=10, exc=err) + waiter.wait_for(_get_port_from_log, timeout=ap_max_activate_time, exc=err) return port def set_control_connection(self, connection): From 49da85ca3a4acb633d9c63abcd43f485905aeb92 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 1 Nov 2021 16:07:57 -0700 Subject: [PATCH 134/200] Fix new project path when enabling gem (#5173) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/CreateProjectCtrl.cpp | 2 +- Code/Tools/ProjectManager/Source/CreateProjectCtrl.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) 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; }; From 4a57b13a0e2ba035ed75a379f3cfc44ebe39e35d Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Mon, 1 Nov 2021 17:11:07 -0700 Subject: [PATCH 135/200] Adding P0 Occlusion Culling Plane test Signed-off-by: Neil Widmaier --- .../Atom/TestSuite_Main_Optimized.py | 4 + ...orComponents_OcclusionCullingPlaneAdded.py | 156 ++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 45298ed563..e2a45f9928 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -54,6 +54,10 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_MeshAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module + @pytest.mark.test_case_id("C36525663") + class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module + @pytest.mark.test_case_id("C32078125") class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py new file mode 100644 index 0000000000..26bff5a289 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py @@ -0,0 +1,156 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +class Tests: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + Occlusion_Culling_Plane_entity_creation = ( + "Occlusion Culling Plane Entity successfully created", + "Occlusion Culling Plane Entity failed to be created") + Occlusion_Culling_Plane_component_added = ( + "Entity has a Occlusion Culling Plane component", + "Entity failed to find Occlusion Culling Plane component") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity(): + """ + Summary: + Tests the Occlusion_Culling_Plane component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create a Occlusion Culling Plane entity with no components. + 2) Add a Occlusion Culling Plane component to Occlusion Culling Plane entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Enter/Exit game mode. + 6) Test IsHidden. + 7) Test IsVisible. + 8) Delete Occlusion Culling Plane entity. + 9) UNDO deletion. + 10) REDO deletion. + 11) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create a Occlusion_Culling_Plane entity with no components. + occlusion_culling_plane_entity = EditorEntity.create_editor_entity(AtomComponentProperties.occlusion_culling_plane()) + Report.critical_result(Tests.Occlusion_Culling_Plane_entity_creation, occlusion_culling_plane_entity.exists()) + + # 2. Add a Occlusion_Culling_Plane component to Occlusion_Culling_Plane entity. + Occlusion_Culling_Plane_component = occlusion_culling_plane_entity.add_component(AtomComponentProperties.occlusion_culling_plane()) + Report.critical_result( + Tests.Occlusion_Culling_Plane_component_added, + occlusion_culling_plane_entity.has_component(AtomComponentProperties.occlusion_culling_plane())) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not occlusion_culling_plane_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, occlusion_culling_plane_entity.exists()) + + # 5. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 6. Test IsHidden. + occlusion_culling_plane_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, occlusion_culling_plane_entity.is_hidden() is True) + + # 7. Test IsVisible. + occlusion_culling_plane_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, occlusion_culling_plane_entity.is_visible() is True) + + # 8. Delete Occlusion_Culling_Plane entity. + occlusion_culling_plane_entity.delete() + Report.result(Tests.entity_deleted, not occlusion_culling_plane_entity.exists()) + + # 9. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, occlusion_culling_plane_entity.exists()) + + # 10. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not occlusion_culling_plane_entity.exists()) + + # 11. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity) From a8efd5da95fef022a388297cc04a4a5ba77395f1 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Mon, 1 Nov 2021 23:42:14 -0700 Subject: [PATCH 136/200] add the correct paths for Light component test and use the 'Base' level instead of 'auto_test' level to resolve remaining issues with screenshot angles Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../PythonTests/Atom/TestSuite_Main_GPU.py | 14 ++--- .../Atom/atom_utils/atom_component_helper.py | 53 +++++++------------ .../Atom/atom_utils/atom_constants.py | 1 + .../tests/hydra_GPUTest_BasicLevelSetup.py | 28 ++-------- .../tests/hydra_GPUTest_LightComponent.py | 2 +- 5 files changed, 27 insertions(+), 71 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py index 534b061b1c..f0e92c7e3e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py @@ -69,7 +69,7 @@ def create_screenshots_archive(screenshot_path): @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ["windows_editor"]) -@pytest.mark.parametrize("level", ["auto_test"]) +@pytest.mark.parametrize("level", ["Base"]) class TestAllComponentsIndepthTests(object): @pytest.mark.parametrize("screenshot_name", ["AtomBasicLevelSetup.ppm"]) @@ -91,10 +91,7 @@ class TestAllComponentsIndepthTests(object): "Viewport is set to the expected size: True", "Exited game mode" ] - unexpected_lines = [ - "Traceback (most recent call last):", - "Screenshot failed" - ] + unexpected_lines = ["Traceback (most recent call last):"] hydra.launch_and_validate_results( request, @@ -149,12 +146,7 @@ class TestAllComponentsIndepthTests(object): golden_images.append(golden_image_path) expected_lines = ["spot_light Controller|Configuration|Shadows|Shadowmap size: SUCCESS"] - unexpected_lines = [ - "Trace::Assert", - "Trace::Error", - "Traceback (most recent call last):", - "Screenshot failed", - ] + unexpected_lines = ["Traceback (most recent call last):"] hydra.launch_and_validate_results( request, TEST_DIRECTORY, diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 5fa558ab1a..0291b3efba 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -116,29 +116,11 @@ def create_basic_atom_level(level_name): helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") - # Create a new level. - new_level_name = level_name - heightmap_resolution = 512 - heightmap_meters_per_pixel = 1 - terrain_texture_resolution = 412 - use_terrain = False - - # Return codes are ECreateLevelResult defined in CryEdit.h - return_code = general.create_level_no_prompt( - new_level_name, heightmap_resolution, heightmap_meters_per_pixel, terrain_texture_resolution, use_terrain) - if return_code == 1: - general.log(f"{new_level_name} level already exists") - elif return_code == 2: - general.log("Failed to create directory") - elif return_code == 3: - general.log("Directory length is too long") - elif return_code != 0: - general.log("Unknown error, failed to create level") - else: - general.log(f"{new_level_name} level created successfully") - - # Enable idle and update viewport. + # Wait for Editor idle loop before executing Python hydra scripts. general.idle_enable(True) + + # Basic setup for opened level. + helper.open_level(level_name="Base") general.idle_wait(1.0) general.update_viewport() general.idle_wait(0.5) # half a second is more than enough for updating the viewport. @@ -205,24 +187,25 @@ def create_basic_atom_level(level_name): components=["Material"], parent_id=default_level.id) azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", ground_plane.id, 32.0) - ground_plane_material_asset_path = os.path.join( - "Materials", "Presets", "PBR", "metal_chrome.azmaterial") - ground_plane_material_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) - ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset_value) - # Work around to add the correct Atom Mesh component + # Work around to add the correct Atom Mesh component and asset. mesh_type_id = azlmbr.globals.property.EditorMeshComponentTypeId ground_plane.components.append( editor.EditorComponentAPIBus( bus.Broadcast, "AddComponentsOfType", ground_plane.id, [mesh_type_id] ).GetValue()[0] ) - ground_plane_mesh_asset_path = os.path.join("Models", "plane.azmodel") + ground_plane_mesh_asset_path = os.path.join("TestData", "Objects", "plane.azmodel") ground_plane_mesh_asset_value = asset.AssetCatalogRequestBus( bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False) ground_plane.get_set_test(1, "Controller|Configuration|Mesh Asset", ground_plane_mesh_asset_value) + # Add Atom Material component and asset. + ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial") + ground_plane_material_asset_value = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False) + ground_plane.get_set_test(0, "Default Material|Material Asset", ground_plane_material_asset_value) + # Create directional_light entity and set the properties directional_light = hydra.Entity("directional_light") directional_light.create_entity( @@ -239,12 +222,8 @@ def create_basic_atom_level(level_name): entity_position=math.Vector3(0.0, 0.0, 1.0), components=["Material"], parent_id=default_level.id) - sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") - sphere_material_asset_value = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) - sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value) - # Work around to add the correct Atom Mesh component + # Work around to add the correct Atom Mesh component and asset. sphere_entity.components.append( editor.EditorComponentAPIBus( bus.Broadcast, "AddComponentsOfType", sphere_entity.id, [mesh_type_id] @@ -255,6 +234,12 @@ def create_basic_atom_level(level_name): bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False) sphere_entity.get_set_test(1, "Controller|Configuration|Mesh Asset", sphere_mesh_asset_value) + # Add Atom Material component and asset. + sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial") + sphere_material_asset_value = asset.AssetCatalogRequestBus( + bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False) + sphere_entity.get_set_test(0, "Default Material|Material Asset", sphere_material_asset_value) + # Create camera component and set the properties camera_entity = hydra.Entity("camera") camera_entity.create_entity( diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 344a0dbd29..3578ec9aa4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -218,6 +218,7 @@ class AtomComponentProperties: properties = { 'name': 'HDR Color Grading', 'requires': [AtomComponentProperties.postfx_layer()], + 'Enable HDR color grading': 'Controller|Configuration|LUT Generation|Enable HDR color grading', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py index 4eb942b903..645447e6de 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py @@ -33,7 +33,7 @@ def run(): 11. Adds a "camera" entity to "default_level" & adds a Camera component with 80 degree FOV and Transform values: Translate - x:5.5m, y:-12.0m, z:9.0m Rotate - x:-27.0, y:-12.0, z:25.0 - 12. Finally enters game mode, takes a screenshot, exits game mode, & saves the level. + 12. Finally enters game mode, takes a screenshot, & exits game mode. :return: None """ import azlmbr.asset as asset @@ -81,33 +81,11 @@ def run(): general.run_console("r_displayInfo=0") general.idle_wait(1.0) - return True - # Wait for Editor idle loop before executing Python hydra scripts. general.idle_enable(True) - # Open the auto_test level. - new_level_name = "auto_test" # Specified in class TestAllComponentsIndepthTests() - heightmap_resolution = 512 - heightmap_meters_per_pixel = 1 - terrain_texture_resolution = 412 - use_terrain = False - - # Return codes are ECreateLevelResult defined in CryEdit.h - return_code = general.create_level_no_prompt( - new_level_name, heightmap_resolution, heightmap_meters_per_pixel, terrain_texture_resolution, use_terrain) - if return_code == 1: - general.log(f"{new_level_name} level already exists") - elif return_code == 2: - general.log("Failed to create directory") - elif return_code == 3: - general.log("Directory length is too long") - elif return_code != 0: - general.log("Unknown error, failed to create level") - else: - general.log(f"{new_level_name} level created successfully") - - # Basic setup for newly created level. + # Basic setup for opened level. + helper.open_level(level_name="Base") after_level_load() initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py index 1c3e6226c1..f69ceb2120 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py @@ -22,7 +22,7 @@ from editor_python_test_tools.editor_test_helper import EditorTestHelper helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper") -LEVEL_NAME = "auto_test" +LEVEL_NAME = "Base" LIGHT_COMPONENT = "Light" LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type' DEGREE_RADIAN_FACTOR = 0.0174533 From 5b0f3450525f42b24564706f9e51d3f8e44d3171 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Tue, 2 Nov 2021 00:03:50 -0700 Subject: [PATCH 137/200] PR fixes to clean up syntax and variable names also to remove a change from another PR Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../PythonTests/Atom/atom_utils/atom_component_helper.py | 8 ++++---- .../Gem/PythonTests/Atom/atom_utils/atom_constants.py | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py index 0291b3efba..50cc15f7e8 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py @@ -77,20 +77,20 @@ def compare_screenshot_similarity( :return: Error string if compared mean value < similarity threshold or screenshot_directory is missing for .zip, otherwise it returns a "Screenshots match" string. """ - error = "Screenshots match" + result = "Screenshots match" if create_zip_archive and not screenshot_directory: - error = 'You must specify a screenshot_directory in order to create a zip archive.\n' + result = 'You must specify a screenshot_directory in order to create a zip archive.\n' mean_similarity = compare_screenshots(test_screenshot, golden_image) if not mean_similarity > similarity_threshold: if create_zip_archive: create_screenshots_archive(screenshot_directory) - error = ( + result = ( f"When comparing the test_screenshot: '{test_screenshot}' " f"to golden_image: '{golden_image}' the mean similarity of '{mean_similarity}' " f"was lower than the similarity threshold of '{similarity_threshold}'. ") - return error + return result def create_basic_atom_level(level_name): diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 3578ec9aa4..344a0dbd29 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -218,7 +218,6 @@ class AtomComponentProperties: properties = { 'name': 'HDR Color Grading', 'requires': [AtomComponentProperties.postfx_layer()], - 'Enable HDR color grading': 'Controller|Configuration|LUT Generation|Enable HDR color grading', } return properties[property] From bf6fd2a6d6b09a87c2478d389efc306d1215ecb5 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Tue, 2 Nov 2021 09:18:42 +0000 Subject: [PATCH 138/200] Add missing reflection calls for various types (#5163) Signed-off-by: hultonha --- .../ContainerEntity/ContainerEntitySystemComponent.cpp | 6 +++++- .../FocusMode/FocusModeSystemComponent.cpp | 6 +++++- .../AzToolsFramework/Tests/BoundsTestComponent.cpp | 7 +++++-- .../Framework/AzToolsFramework/Tests/BoundsTestComponent.h | 1 - 4 files changed, 15 insertions(+), 5 deletions(-) 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/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 From de6af361ab15a9fc504518368e5a8fca2db5a065 Mon Sep 17 00:00:00 2001 From: hultonha <82228511+hultonha@users.noreply.github.com> Date: Tue, 2 Nov 2021 09:19:06 +0000 Subject: [PATCH 139/200] Do not clear input channels everytime focus changes (#5044) * remove HandleFocusChange from FocusIn/Out events in QtEventToAzInputManager Signed-off-by: hultonha * ensure we clear input channels when application state changes Signed-off-by: hultonha * wip changes for focus switching tests Signed-off-by: hultonha * updates to test to verify focus change not affecting input Signed-off-by: hultonha * add test to ensure input is not cleared when focus changes Signed-off-by: hultonha * ensure key press goes to correct widget Signed-off-by: hultonha * add test to verify input is cleared when application state changes Signed-off-by: hultonha * clear input for all types of application state change Signed-off-by: hultonha * update input key for focus test Signed-off-by: hultonha * use the Settings Registry to tell the InputSystemComponent to disable various devices Signed-off-by: hultonha * update how we simulate the application state change event Signed-off-by: hultonha * revert Settings Registry changes Signed-off-by: hultonha --- .../test_ViewportManipulatorController.cpp | 78 ++++++++++++++++++- .../Input/QtEventToAzInputManager.cpp | 18 +++-- .../Input/QtEventToAzInputManager.h | 5 +- 3 files changed, 91 insertions(+), 10 deletions(-) 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/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(); From 0ccd55f9459f50a9d0906e8d875943a7bc8e74c2 Mon Sep 17 00:00:00 2001 From: moraaar Date: Tue, 2 Nov 2021 09:28:31 +0000 Subject: [PATCH 140/200] Added PAL to blast and whitebox tests to only enable automated tests on supported platforms: windows only at the moment. (#5165) Signed-off-by: moraaar --- AutomatedTesting/Gem/PythonTests/Blast/CMakeLists.txt | 6 +++++- .../PythonTests/Blast/Platform/Android/PAL_android.cmake | 9 +++++++++ .../Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake | 9 +++++++++ .../Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake | 9 +++++++++ .../PythonTests/Blast/Platform/Windows/PAL_windows.cmake | 9 +++++++++ .../Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake | 9 +++++++++ AutomatedTesting/Gem/PythonTests/WhiteBox/CMakeLists.txt | 6 +++++- .../WhiteBox/Platform/Android/PAL_android.cmake | 9 +++++++++ .../PythonTests/WhiteBox/Platform/Linux/PAL_linux.cmake | 9 +++++++++ .../Gem/PythonTests/WhiteBox/Platform/Mac/PAL_mac.cmake | 9 +++++++++ .../WhiteBox/Platform/Windows/PAL_windows.cmake | 9 +++++++++ .../Gem/PythonTests/WhiteBox/Platform/iOS/PAL_ios.cmake | 9 +++++++++ 12 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Blast/Platform/Android/PAL_android.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/Blast/Platform/Linux/PAL_linux.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/Blast/Platform/Mac/PAL_mac.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/Blast/Platform/Windows/PAL_windows.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/Blast/Platform/iOS/PAL_ios.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Android/PAL_android.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Linux/PAL_linux.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Mac/PAL_mac.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/Windows/PAL_windows.cmake create mode 100644 AutomatedTesting/Gem/PythonTests/WhiteBox/Platform/iOS/PAL_ios.cmake 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/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) From d52ce49dcb827c04150a6f11b7cceead9f61a43c Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Tue, 2 Nov 2021 09:27:10 -0500 Subject: [PATCH 141/200] Terrain macro material fixes (#5182) * Minor fixes for macro materials - When macro image views are no longer used, they will explicitely be set to nullptr - limiting for loop in shader to the number of macro materials total so it doesn't read unitialized memory Signed-off-by: Ken Pruiksma * Removing parts of the terrain shader no longer used. Signed-off-by: Ken Pruiksma * Fixing normalization in shaders, adding default valus for all structs used in SRGs. Signed-off-by: Ken Pruiksma --- .../Terrain/TerrainPBR_ForwardPass.azsl | 18 ++++++------------ .../TerrainMacroMaterialComponent.cpp | 2 ++ .../TerrainFeatureProcessor.cpp | 9 ++++++++- .../TerrainRenderer/TerrainFeatureProcessor.h | 18 +++++++++--------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl index 750cd2fb29..9cfa568b9a 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl @@ -22,11 +22,9 @@ struct VSOutput { float4 m_position : SV_Position; float3 m_normal: NORMAL; - float3 m_tangent : TANGENT; - float3 m_bitangent : BITANGENT; float3 m_worldPosition : UV0; - float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV2; float2 m_uv : UV1; + float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV2; }; VSOutput TerrainPBR_MainPassVS(VertexInput IN) @@ -47,9 +45,9 @@ VSOutput TerrainPBR_MainPassVS(VertexInput IN) float down = GetHeight(origUv + terrainData.m_uvStep * float2( 0.0f, 1.0f)); float left = GetHeight(origUv + terrainData.m_uvStep * float2(-1.0f, 0.0f)); - OUT.m_bitangent = normalize(float3(0.0, terrainData.m_sampleSpacing * 2.0f, down - up)); - OUT.m_tangent = normalize(float3(terrainData.m_sampleSpacing * 2.0f, 0.0, right - left)); - OUT.m_normal = cross(OUT.m_tangent, OUT.m_bitangent); + float3 bitangent = normalize(float3(0.0, terrainData.m_sampleSpacing * 2.0f, down - up)); + float3 tangent = normalize(float3(terrainData.m_sampleSpacing * 2.0f, 0.0, right - left)); + OUT.m_normal = normalize(cross(tangent, bitangent)); OUT.m_uv = uv; // directional light shadow @@ -75,18 +73,14 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) surface.position = IN.m_worldPosition.xyz; float viewDistance = length(ViewSrg::m_worldPosition - surface.position); float detailFactor = saturate((viewDistance - TerrainMaterialSrg::m_detailFadeDistance) / max(TerrainMaterialSrg::m_detailFadeLength, EPSILON)); - - ObjectSrg::TerrainData terrainData = ObjectSrg::m_terrainData; - float2 origUv = lerp(terrainData.m_uvMin, terrainData.m_uvMax, IN.m_uv); - origUv.y = 1.0 - origUv.y; float2 detailUv = IN.m_uv * TerrainMaterialSrg::m_detailTextureMultiplier; // ------- Normal ------- - float3 macroNormal = IN.m_normal; + float3 macroNormal = normalize(IN.m_normal); // ------- Macro Color / Normal ------- float3 macroColor = TerrainMaterialSrg::m_baseColor.rgb; - [unroll] for (uint i = 0; i < 4; ++i) + [unroll] for (uint i = 0; i < 4 && (i < ObjectSrg::m_macroMaterialCount); ++i) { float2 macroUvMin = ObjectSrg::m_macroMaterialData[i].m_uvMin; float2 macroUvMax = ObjectSrg::m_macroMaterialData[i].m_uvMax; diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp index 0d161b6b2b..a65cbad50b 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp @@ -248,6 +248,7 @@ namespace Terrain { m_configuration.m_macroColorAsset = asset; m_colorImage = AZ::RPI::StreamingImage::FindOrCreate(m_configuration.m_macroColorAsset); + m_colorImage->GetRHIImage()->SetName(AZ::Name(m_configuration.m_macroColorAsset.GetHint())); // Clear the texture asset reference to make sure we don't prevent hot-reloading. m_configuration.m_macroColorAsset.Release(); @@ -256,6 +257,7 @@ namespace Terrain { m_configuration.m_macroNormalAsset = asset; m_normalImage = AZ::RPI::StreamingImage::FindOrCreate(m_configuration.m_macroNormalAsset); + m_normalImage->GetRHIImage()->SetName(AZ::Name(m_configuration.m_macroNormalAsset.GetHint())); // Clear the texture asset reference to make sure we don't prevent hot-reloading. m_configuration.m_macroColorAsset.Release(); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp index 1b13d3bb98..73f1c3967c 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.cpp @@ -535,7 +535,9 @@ namespace Terrain sectorData.m_srg->SetConstant(m_terrainDataIndex, terrainDataForSrg); AZStd::array macroMaterialData; - for (uint32_t i = 0; i < sectorData.m_macroMaterials.size(); ++i) + + uint32_t i = 0; + for (; i < sectorData.m_macroMaterials.size(); ++i) { const MacroMaterialData& materialData = m_macroMaterials.GetData(sectorData.m_macroMaterials.at(i)); ShaderMacroMaterialData& shaderData = macroMaterialData.at(i); @@ -564,6 +566,11 @@ namespace Terrain // set flags for which images are used. shaderData.m_mapsInUse = (colorImageView ? ColorImageUsed : 0) | (normalImageView ? NormalImageUsed : 0); } + for (; i < sectorData.m_macroMaterials.capacity(); ++i) + { + sectorData.m_srg->SetImageView(m_macroColorMapIndex, nullptr, i); + sectorData.m_srg->SetImageView(m_macroNormalMapIndex, nullptr, i); + } sectorData.m_srg->SetConstantArray(m_macroMaterialDataIndex, macroMaterialData); sectorData.m_srg->SetConstant(m_macroMaterialCountIndex, aznumeric_cast(sectorData.m_macroMaterials.size())); diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h index 91e3ce9a5c..f6836fdd28 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainFeatureProcessor.h @@ -68,18 +68,18 @@ namespace Terrain struct ShaderTerrainData // Must align with struct in Object Srg { - AZStd::array m_uvMin; - AZStd::array m_uvMax; - AZStd::array m_uvStep; - float m_sampleSpacing; - float m_heightScale; + AZStd::array m_uvMin{ 0.0f, 0.0f }; + AZStd::array m_uvMax{ 1.0f, 1.0f }; + AZStd::array m_uvStep{ 1.0f, 1.0f }; + float m_sampleSpacing{ 1.0f }; + float m_heightScale{ 1.0f }; }; - struct ShaderMacroMaterialData + struct ShaderMacroMaterialData // Must align with struct in Object Srg { - AZStd::array m_uvMin; - AZStd::array m_uvMax; - float m_normalFactor; + AZStd::array m_uvMin{ 0.0f, 0.0f }; + AZStd::array m_uvMax{ 1.0f, 1.0f }; + float m_normalFactor{ 0.0f }; uint32_t m_flipNormalX{ 0 }; // bool in shader uint32_t m_flipNormalY{ 0 }; // bool in shader uint32_t m_mapsInUse{ 0b00 }; // 0b01 = color, 0b10 = normal From 6a6d8e6b39c1440c294771972ffe4261f801ae53 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Tue, 2 Nov 2021 10:57:31 -0500 Subject: [PATCH 142/200] Fixed unit_test_regiser.py test on Linux/Mac (#5031) Added pathlib.Path.resolve() calls to make sure the compared paths were both absolute Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- scripts/o3de/tests/unit_test_register.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/o3de/tests/unit_test_register.py b/scripts/o3de/tests/unit_test_register.py index 36139c0afa..954dd852f8 100644 --- a/scripts/o3de/tests/unit_test_register.py +++ b/scripts/o3de/tests/unit_test_register.py @@ -192,9 +192,9 @@ class TestRegisterGem: def test_register_gem_auto_detects_manifest_update(self, gem_path, expected_manifest_file,expected_result): def save_o3de_manifest(manifest_data: dict, manifest_path: pathlib.Path = None) -> bool: - if manifest_path == TestRegisterGem.project_path / 'project.json': + if manifest_path == pathlib.Path(TestRegisterGem.project_path).resolve() / 'project.json': self.project_data = manifest_data - elif manifest_path == TestRegisterGem.engine_path / 'engine.json': + elif manifest_path == pathlib.Path(TestRegisterGem.engine_path).resolve() / 'engine.json': self.engine_data = manifest_data else: self.o3de_manifest_data = manifest_data @@ -240,11 +240,11 @@ class TestRegisterGem: assert result == expected_result if expected_manifest_file == pathlib.PurePath('o3de_manifest.json'): - assert gem_path in map(lambda subdir: pathlib.PurePath(subdir), + assert pathlib.Path(gem_path).resolve() in map(lambda subdir: pathlib.PurePath(subdir), self.o3de_manifest_data.get('external_subdirectories', [])) elif expected_manifest_file == pathlib.PurePath('project.json'): - assert gem_path in map(lambda subdir: pathlib.PurePath(TestRegisterGem.project_path) / subdir, + assert gem_path in map(lambda subdir: TestRegisterGem.project_path / subdir, self.project_data.get('external_subdirectories', [])) elif expected_manifest_file == pathlib.PurePath('engine.json'): - assert gem_path in map(lambda subdir: pathlib.PurePath(TestRegisterGem.engine_path) / subdir, + assert gem_path in map(lambda subdir: TestRegisterGem.engine_path / subdir, self.engine_data.get('external_subdirectories', [])) From 32bebe1c8c6bee5a031bf2834a66cf041d5ed222 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 2 Nov 2021 08:59:19 -0700 Subject: [PATCH 143/200] bugifx: resolve crash with project manager (#5151) - system allocator not configured in environment for AZQtComponents - WA_DeleteOnClose will destroy the toast dialog causing a crashing when ToastNotificationsView tries to access the pointer issue: https://github.com/o3de/o3de/issues/5129 Signed-off-by: Michael Pollind --- .../AzQtComponents/Components/ToastNotification.cpp | 1 - .../AzQtComponents/Components/ToastNotification.h | 3 +-- .../AzQtComponents/Components/ToastNotificationConfiguration.h | 1 - .../UI/Notifications/ToastNotificationsView.cpp | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) 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/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; From 6d592d78cdc3bd7e2e42127a87de7eacea322ba8 Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Tue, 2 Nov 2021 09:03:38 -0700 Subject: [PATCH 144/200] Fixes for release builds with DCO fix (#5164) * This set of changes is work toward allowing release builds to work with asset bundler generated bundles and legacy, non-prefab levels. This requires some other in-flight changes before this work is complete. Updated engine seed list + fixed automated test ComponentApplicationLifecycle has the ability to automatically register events if asked to register a handler and the event doesn't exist. This is only intended for cases where you need to register a handler early in startup before the settings registry file is loaded. Added two new lifecycle events: One after the system entity has been activated, and one after the system interface has been created. If you load an archive before the system entity has been activated, archive.cpp caches information about those archives until that time, so it can finish registration. This is because the serialization system and BundlingSystemComponent both need to be available to do this registration, but the bundles have to be loaded before those are initialized so that the settings registry file can be loaded. Fixed an error were mounted pak files were searching for levels.pak and not level.pak, and not finding them. I'm pretty sure this logic doesn't do anything functional either way, but I've been testing legacy levels with this change and they work now. Moved wildcard pak loading to where engine.pak is loaded. This is because the settings registry file that defines the IO stack to spin up must be available early in application startup, and this file must be within a mounted pak file. If you're using asset bundler generated bundles, they need to be loaded at this time so that file can be loaded. Atom's BootstrapSystemComponent.cpp no longer initializes on AssetCatalogLoaded, and instead initializes on the ApplicationLifecycle event SystemInterfaceCreated. This is because the base assetcatalog.xml file is really just a development time concept, this file should not be used in packaged release builds, because those builds will make use of delta catalogs in each bundle loaded. The asset catalog contains the list of all assets that were in the cache at development time, and this contains content that developers don't want to ship, and they may want to specifically hide from their customers, so data miners don't find secrets about upcoming game content. Recovering from a branch that had incorrect DCO Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Fixed an incorrect ebus disconnect and removed an include that's no longer needed Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Fixed a copy and paste typo from trying to recover the previous pull request Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Updated product IDs for the settings registry builder to no longer collide with the JSON builder. Now they are based on a hash of the configuration. Updated the engine default seed list to include the new asset ID info for the renamed bootstrap file Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Updated the path to the application lifecycle events, because runtime settings aren't included in the merged bootstrap file. Addressed some feedback on printing out a string view on an error Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Removed a test that uses old assets that aren't relevant. We may not need this test anymore, but if we do we've backlogged a task to create a new test to cover this behavior without using old assets. Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Renamed SystemInterfaceCreated event to LegacySystemInterfaceCreated Removed SystemEntityActivated event. Now that I have the rest of the fixes in this pull request, this new event wasn't needed, the already existing SystemComponentsActivated event does what I need. Changed list to vector Signed-off-by: stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- Assets/Engine/Engine_Dependencies.xml | 23 +- Assets/Engine/SeedAssetList.seed | 877 ++++++------------ .../asset_processor_batch_dependency_tests.py | 76 -- Code/Editor/CryEdit.cpp | 6 + .../ComponentApplicationLifecycle.cpp | 12 +- .../Component/ComponentApplicationLifecycle.h | 6 +- .../AzFramework/Application/Application.cpp | 1 - .../AzFramework/Archive/Archive.cpp | 76 +- .../AzFramework/AzFramework/Archive/Archive.h | 37 + .../Application/GameApplication.cpp | 7 + Code/LauncherUnified/Launcher.cpp | 3 + Code/Legacy/CrySystem/System.h | 2 +- Code/Legacy/CrySystem/SystemInit.cpp | 25 +- .../SettingsRegistryBuilder.cpp | 10 +- .../Code/Source/BootstrapSystemComponent.cpp | 25 +- .../Code/Source/BootstrapSystemComponent.h | 15 +- .../PreviewRendererSystemComponent.cpp | 23 +- .../PreviewRendererSystemComponent.h | 5 - Registry/application_lifecycle_events.setreg | 35 +- 19 files changed, 470 insertions(+), 794 deletions(-) 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/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/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/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/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/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/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/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/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/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp b/Gems/Atom/Bootstrap/Code/Source/BootstrapSystemComponent.cpp index ed3241b312..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) 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/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp index fc5b31297a..d46e7b27be 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.cpp @@ -47,30 +47,27 @@ namespace AtomToolsFramework void PreviewRendererSystemComponent::Activate() { - AzFramework::AssetCatalogEventBus::Handler::BusConnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusConnect(); PreviewRendererSystemRequestBus::Handler::BusConnect(); + + AZ::TickBus::QueueFunction( + [this]() + { + if (!m_previewRenderer) + { + m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( + "PreviewRendererSystemComponent Preview Scene", "PreviewRendererSystemComponent Preview Pipeline")); + } + }); } void PreviewRendererSystemComponent::Deactivate() { PreviewRendererSystemRequestBus::Handler::BusDisconnect(); AzFramework::ApplicationLifecycleEvents::Bus::Handler::BusDisconnect(); - AzFramework::AssetCatalogEventBus::Handler::BusDisconnect(); m_previewRenderer.reset(); } - void PreviewRendererSystemComponent::OnCatalogLoaded([[maybe_unused]] const char* catalogFile) - { - AZ::TickBus::QueueFunction([this](){ - if (!m_previewRenderer) - { - m_previewRenderer.reset(aznew AtomToolsFramework::PreviewRenderer( - "PreviewRendererSystemComponent Preview Scene", "PreviewRendererSystemComponent Preview Pipeline")); - } - }); - } - void PreviewRendererSystemComponent::OnApplicationAboutToStop() { m_previewRenderer.reset(); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h index 8110d84794..0b145bbdf1 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PreviewRenderer/PreviewRendererSystemComponent.h @@ -9,7 +9,6 @@ #pragma once #include -#include #include #include #include @@ -19,7 +18,6 @@ namespace AtomToolsFramework //! System component that manages a global PreviewRenderer. class PreviewRendererSystemComponent final : public AZ::Component - , public AzFramework::AssetCatalogEventBus::Handler , public AzFramework::ApplicationLifecycleEvents::Bus::Handler , public PreviewRendererSystemRequestBus::Handler { @@ -38,9 +36,6 @@ namespace AtomToolsFramework void Deactivate() override; private: - // AzFramework::AssetCatalogEventBus::Handler overrides ... - void OnCatalogLoaded(const char* catalogFile) override; - // AzFramework::ApplicationLifecycleEvents overrides... void OnApplicationAboutToStop() override; diff --git a/Registry/application_lifecycle_events.setreg b/Registry/application_lifecycle_events.setreg index 58baf267b0..0d9cd0f170 100644 --- a/Registry/application_lifecycle_events.setreg +++ b/Registry/application_lifecycle_events.setreg @@ -7,24 +7,23 @@ // related to the event { "O3DE" : { - "Runtime": { - "Application": { - "LifecycleEvents": { - "SystemComponentsActivated": {}, - "SystemComponentsDeactivated": {}, - "ReflectionManagerAvailable": {}, - "ReflectionManagerUnavailable": {}, - "SystemAllocatorCreated": {}, - "SystemAllocatorPendingDestruction": {}, - "SettingsRegistryAvailable": {}, - "SettingsRegistryUnavailable": {}, - "ConsoleAvailable": {}, - "ConsoleUnavailable": {}, - "GemsLoaded": {}, - "GemsUnloaded": {}, - "FileIOAvailable": {}, - "FileIOUnavailable": {} - } + "Application": { + "LifecycleEvents": { + "SystemComponentsActivated": {}, + "SystemComponentsDeactivated": {}, + "ReflectionManagerAvailable": {}, + "ReflectionManagerUnavailable": {}, + "SystemAllocatorCreated": {}, + "SystemAllocatorPendingDestruction": {}, + "SettingsRegistryAvailable": {}, + "SettingsRegistryUnavailable": {}, + "ConsoleAvailable": {}, + "ConsoleUnavailable": {}, + "GemsLoaded": {}, + "GemsUnloaded": {}, + "FileIOAvailable": {}, + "FileIOUnavailable": {}, + "LegacySystemInterfaceCreated": {} } } } From 6da75821c580aa1bb2a646a36285d6c7c168201d Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 2 Nov 2021 11:22:03 -0500 Subject: [PATCH 145/200] Move Exception PrintCallstack call before any ebus calls to help track down issue with crash during an exception (#5188) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../Platform/Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 9b78da222c..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 @@ -184,6 +184,8 @@ namespace AZ::Debug 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; @@ -195,7 +197,7 @@ namespace AZ::Debug // 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. From 63e68f02e7531bfa2ed61b5cb50d1940a35c232b Mon Sep 17 00:00:00 2001 From: srikappa-amzn <82230713+srikappa-amzn@users.noreply.github.com> Date: Tue, 2 Nov 2021 21:53:43 +0530 Subject: [PATCH 146/200] Add benchmarks for SpawnAllEntities call in SpawnableEntitiesManager (#5141) * Add benchmarks for SpawnAllEntities call in SpawnableEntitiesManager Signed-off-by: srikappa-amzn * Minor changes to SpawnAllEntities benchmarks setup Signed-off-by: srikappa-amzn * Used aznumeric_cast and improved a function name Signed-off-by: srikappa-amzn * Fixed an invalid converstion from uint64_t to unsigned int Signed-off-by: srikappa-amzn --- .../Spawnable/SpawnAllEntitiesBenchmarks.cpp | 130 ++++++++++++++++++ .../Spawnable/SpawnableBenchmarkFixture.cpp | 69 ++++++++++ .../Spawnable/SpawnableBenchmarkFixture.h | 44 ++++++ .../Tests/aztoolsframeworktests_files.cmake | 3 + 4 files changed, 246 insertions(+) create mode 100644 Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnAllEntitiesBenchmarks.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.cpp create mode 100644 Code/Framework/AzToolsFramework/Tests/Prefab/Benchmark/Spawnable/SpawnableBenchmarkFixture.h 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 From 255e6894dcf83cac730df08f4c5765b70a9887cf Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Tue, 2 Nov 2021 12:48:51 -0500 Subject: [PATCH 147/200] {} adding behavior for GraphData BoneData (#5061) * adding behavior for AZ::SceneData::GraphData::BoneData * adding behavior for AZ::SceneData::GraphData::RootBoneData Signed-off-by: jackalbe <23512001+jackalbe@users.noreply.github.com> --- .../SceneAPI/SceneData/GraphData/BoneData.cpp | 11 ++++ .../SceneData/GraphData/RootBoneData.cpp | 11 ++++ .../GraphData/GraphDataBehaviorTests.cpp | 53 ++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) 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)"); + } } } } From e11b1e2c9c5434c28934bae268082d95e6e6812f Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 2 Nov 2021 12:51:28 -0500 Subject: [PATCH 148/200] [LYN-7774] wildcard source dependencies not refreshing with new files (#5054) * Fix handling of absolute path dependencies when a newly added file satisfies a previously added dependency Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Fixed relative path wildcard dependencies matching absolute paths Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update extra unit test to only run on windows since this problem doesn't apply to other OSes Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AssetManager/assetProcessorManager.cpp | 23 +++-- .../AssetProcessorManagerTest.cpp | 88 +++++++++++++++++-- .../assetmanager/AssetProcessorManagerTest.h | 1 + 3 files changed, 102 insertions(+), 10 deletions(-) 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/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 0b02b168dc..9c20d99243 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -5318,6 +5318,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 +5338,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 +5372,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 +5506,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..d5afd8520f 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h @@ -135,6 +135,7 @@ struct WildcardSourceDependencyTest : AssetProcessorManagerTest { bool Test(const AZStd::string& dependencyPath, AZStd::vector& resolvedPaths); + AZStd::vector FileAddedTest(const QString& path); void SetUp() override; }; From 3d61db8d1dde20d06028aa5271abdb8f87c63783 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 2 Nov 2021 12:51:36 -0500 Subject: [PATCH 149/200] [LYN-7245] AP unit test segfault - Clean up debug messages (#5192) * Added newline to debug prints. Added additional debug prints based on previous segfault log Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add more debug messaging Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add db path to output Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../native/AssetDatabase/AssetDatabase.cpp | 5 ++++- .../assetmanager/AssetProcessorManagerTest.cpp | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) 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/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 9c20d99243..656d7cab4e 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -241,7 +241,9 @@ 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())); + AZ_Printf("UnitTest", "APM ready\n"); m_assertAbsorber.Clear(); m_isIdling = false; @@ -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) From cf1d13fa43f3e6c62447ec696f505bd816d94212 Mon Sep 17 00:00:00 2001 From: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:38:38 -0400 Subject: [PATCH 150/200] AutomatedTesting - adding Hair to MainPipeline (#5200) * AutomatedTesting - adding Hair to MainPipeline Signed-off-by: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> * Hair - securing default value of render technique to be ShortCut Signed-off-by: Adi Bar-Lev <82479970+Adi-Amazon@users.noreply.github.com> --- AutomatedTesting/Passes/MainPipeline.pass | 117 ++++++++++++++++-- .../Code/Rendering/HairFeatureProcessor.h | 2 +- 2 files changed, 106 insertions(+), 13 deletions(-) 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/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h index 70e37a7863..8c19b706a9 100644 --- a/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h +++ b/Gems/AtomTressFX/Code/Rendering/HairFeatureProcessor.h @@ -217,7 +217,7 @@ namespace AZ bool m_forceClearRenderData = false; bool m_initialized = false; bool m_isEnabled = true; - bool m_usePPLLRenderTechnique = true; + bool m_usePPLLRenderTechnique = false; static uint32_t s_instanceCount; HairGlobalSettings m_hairGlobalSettings; From 5c072a5d51e2cabf5210f7609ec9ce264124f6ab Mon Sep 17 00:00:00 2001 From: "rgba16f [Amazon]" <82187279+rgba16f@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:02:08 -0500 Subject: [PATCH 151/200] Part 2 of enabling Atom to use TaskGraph Enable Atom CullingScene to use TaskGraph Enable Atom PNG save to use TaskGraph for red/blue color channel swap on save out. Signed-off-by: rgba16f <82187279+rgba16f@users.noreply.github.com> --- .../AzCore/AzCore/Task/TaskExecutor.cpp | 6 +- .../AzCore/AzCore/Task/TaskGraph.cpp | 40 ++ Code/Framework/AzCore/AzCore/Task/TaskGraph.h | 8 +- .../AzCore/AzCore/Task/TaskGraph.inl | 5 - Code/Framework/AzCore/Tests/TaskTests.cpp | 11 +- .../Source/FrameCaptureSystemComponent.cpp | 83 ++- .../Code/Include/Atom/RPI.Public/Culling.h | 19 +- .../RPI/Code/Include/Atom/RPI.Public/Scene.h | 7 +- .../RPI/Code/Source/RPI.Public/Culling.cpp | 524 +++++++++++------- .../Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 79 +-- 10 files changed, 502 insertions(+), 280 deletions(-) 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/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/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp index a9bb7271ab..8b016410aa 100644 --- a/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/FrameCaptureSystemComponent.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include #include @@ -50,6 +52,15 @@ namespace AZ "Sets the compression level for saving png screenshots. Valid values are from 0 to 8" ); + AZ_CVAR(int, + r_pngCompressionNumThreads, + 8, // Number of threads to use for the png r<->b channel data swap + nullptr, + ConsoleFunctorFlags::Null, + "Sets the number of threads for saving png screenshots. Valid values are from 1 to 128, although less than or equal the number of hw threads is recommended" + ); + + FrameCaptureOutputResult PngFrameCaptureOutput( const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult) { @@ -65,33 +76,67 @@ namespace AZ buffer = AZStd::make_shared>(readbackResult.m_dataBuffer->size()); AZStd::copy(readbackResult.m_dataBuffer->begin(), readbackResult.m_dataBuffer->end(), buffer->begin()); - - AZ::JobCompletion jobCompletion; - const int numThreads = 8; + const int numThreads = r_pngCompressionNumThreads; const int numPixelsPerThread = static_cast(buffer->size() / numChannels / numThreads); - for (int i = 0; i < numThreads; ++i) + + AZ::TaskGraphActiveInterface* taskGraphActiveInterface = AZ::Interface::Get(); + bool taskGraphActive = taskGraphActiveInterface && taskGraphActiveInterface->IsTaskGraphActive(); + + if (taskGraphActive) + { + static const AZ::TaskDescriptor pngTaskDescriptor{"PngWriteOutChannelSwap", "Graphics"}; + AZ::TaskGraph taskGraph; + for (int i = 0; i < numThreads; ++i) + { + int startPixel = i * numPixelsPerThread; + + taskGraph.AddTask( + pngTaskDescriptor, + [&, startPixel]() + { + for (int pixelOffset = 0; pixelOffset < numPixelsPerThread; ++pixelOffset) + { + if (startPixel * numChannels + numChannels < buffer->size()) + { + AZStd::swap( + buffer->data()[(startPixel + pixelOffset) * numChannels], + buffer->data()[(startPixel + pixelOffset) * numChannels + 2] + ); + } + } + }); + } + AZ::TaskGraphEvent taskGraphFinishedEvent; + taskGraph.Submit(&taskGraphFinishedEvent); + taskGraphFinishedEvent.Wait(); + } + else { - int startPixel = i * numPixelsPerThread; + AZ::JobCompletion jobCompletion; + for (int i = 0; i < numThreads; ++i) + { + int startPixel = i * numPixelsPerThread; - AZ::Job* job = AZ::CreateJobFunction( - [&, startPixel, numPixelsPerThread]() - { - for (int pixelOffset = 0; pixelOffset < numPixelsPerThread; ++pixelOffset) + AZ::Job* job = AZ::CreateJobFunction( + [&, startPixel]() { - if (startPixel * numChannels + numChannels < buffer->size()) + for (int pixelOffset = 0; pixelOffset < numPixelsPerThread; ++pixelOffset) { - AZStd::swap( - buffer->data()[(startPixel + pixelOffset) * numChannels], - buffer->data()[(startPixel + pixelOffset) * numChannels + 2] - ); + if (startPixel * numChannels + numChannels < buffer->size()) + { + AZStd::swap( + buffer->data()[(startPixel + pixelOffset) * numChannels], + buffer->data()[(startPixel + pixelOffset) * numChannels + 2] + ); + } } - } - }, true, nullptr); + }, true, nullptr); - job->SetDependent(&jobCompletion); - job->Start(); + job->SetDependent(&jobCompletion); + job->Start(); + } + jobCompletion.StartAndWaitForCompletion(); } - jobCompletion.StartAndWaitForCompletion(); } Utils::PngFile image = Utils::PngFile::Create(readbackResult.m_imageDescriptor.m_size, format, *buffer); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h index 82e9c733c8..44b1425c7a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -38,6 +38,8 @@ namespace AZ { class Job; + class TaskGraphActiveInterface; + class TaskGraph; namespace RHI { @@ -256,7 +258,13 @@ namespace AZ //! Must be called between BeginCulling() and EndCulling(), once for each active scene/view pair. //! Will create child jobs under the parentJob to do the processing in parallel. //! Can be called in parallel (i.e. to perform culling on multiple views at the same time). - void ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob); + void ProcessCullablesJobs(const Scene& scene, View& view, AZ::Job& parentJob); + + //! Performs render culling and lod selection for a View, then adds the visible renderpackets to that View. + //! Must be called between BeginCulling() and EndCulling(), once for each active scene/view pair. + //! Will create child task graphs that signal the TaskGraphEvent to do the processing in parallel. + //! Can be called in parallel (i.e. to perform culling on multiple views at the same time). + void ProcessCullablesTG(const Scene& scene, View& view, AZ::TaskGraph& taskGraph); //! Adds a Cullable to the underlying visibility system(s). //! Must be called at least once on initialization and whenever a Cullable's position or bounds is changed. @@ -276,17 +284,20 @@ namespace AZ return m_debugCtx; } - static const size_t WorkListCapacity = 5; - using WorkListType = AZStd::fixed_vector; - protected: size_t CountObjectsInScene(); + private: + void BeginCullingTaskGraph(const AZStd::vector& views); + void BeginCullingJobs(const AZStd::vector& views); + void ProcessCullablesCommon(const Scene& scene, View& view, AZ::Frustum& frustum, void*& maskedOcclusionCulling); + const Scene* m_parentScene = nullptr; AzFramework::IVisibilityScene* m_visScene = nullptr; CullingDebugContext m_debugCtx; AZStd::concurrency_checker m_cullDataConcurrencyCheck; OcclusionPlaneVector m_occlusionPlanes; + AZ::TaskGraphActiveInterface* m_taskGraphActive = nullptr; }; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h index f86383101a..21e446feda 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Scene.h @@ -200,8 +200,8 @@ namespace AZ // This function is called every time scene's render pipelines change. void RebuildPipelineStatesLookup(); - // Helper function to wait for end of TaskGraph - void WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn = nullptr); + // Helper function to wait for end of TaskGraph and then delete the TaskGraphEvent + void WaitAndCleanTGEvent(AZStd::unique_ptr&& completionTGEvent); // Helper function for wait and clean up a completion job void WaitAndCleanCompletionJob(AZ::JobCompletion*& completionJob); @@ -230,8 +230,7 @@ namespace AZ AZStd::vector m_pipelines; // CPU simulation TaskGraphEvent to wait for completion of all the simulation tasks - AZ::TaskGraphEvent m_simulationFinishedTGEvent; - AZStd::atomic_bool m_simulationFinishedWorkActive = false; + AZStd::unique_ptr m_simulationFinishedTGEvent; // CPU simulation job completion for track all feature processors' simulation jobs AZ::JobCompletion* m_simulationCompletion = nullptr; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index ac6b10694e..65508b6371 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED @@ -265,89 +267,71 @@ namespace AZ return m_visScene->GetEntryCount(); } - class AddObjectsToViewJob final - : public Job + + struct WorklistData { - public: - AZ_CLASS_ALLOCATOR(AddObjectsToViewJob, ThreadPoolAllocator, 0); + CullingDebugContext* m_debugCtx = nullptr; + const Scene* m_scene = nullptr; + View* m_view = nullptr; + Frustum m_frustum; +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; +#endif + }; - struct JobData - { - CullingDebugContext* m_debugCtx = nullptr; - const Scene* m_scene = nullptr; - View* m_view = nullptr; - Frustum m_frustum; + static AZStd::shared_ptr MakeWorklistData( + CullingDebugContext& debugCtx, + const Scene& scene, + View& view, + Frustum& frustum, + void* maskedOcclusionCulling) + { + AZStd::shared_ptr worklistData = AZStd::make_shared(); + worklistData->m_debugCtx = &debugCtx; + worklistData->m_scene = &scene; + worklistData->m_view = &view; + worklistData->m_frustum = frustum; #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - MaskedOcclusionCulling* m_maskedOcclusionCulling = nullptr; + worklistData->m_maskedOcclusionCulling = static_cast(maskedOcclusionCulling); #endif - }; + return worklistData; + } + + constexpr size_t WorkListCapacity = 5; + using WorkListType = AZStd::fixed_vector; - private: - const AZStd::shared_ptr m_jobData; - CullingScene::WorkListType m_worklist; +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + static MaskedOcclusionCulling::CullingResult TestOcclusionCulling( + const AZStd::shared_ptr& worklistData, + AzFramework::VisibilityEntry* visibleEntry); +#endif - public: - AddObjectsToViewJob(const AZStd::shared_ptr& jobData, CullingScene::WorkListType& worklist) - : Job(true, nullptr) //auto-deletes, no JobContext - , m_jobData(jobData) - , m_worklist(worklist) - { - } + static void ProcessWorklist(const AZStd::shared_ptr& worklistData, const WorkListType& worklist) + { + AZ_PROFILE_SCOPE(RPI, "AddObjectsToViewJob: Process"); - //work function - void Process() override - { - AZ_PROFILE_SCOPE(RPI, "AddObjectsToViewJob: Process"); + const View::UsageFlags viewFlags = worklistData->m_view->GetUsageFlags(); + const RHI::DrawListMask drawListMask = worklistData->m_view->GetDrawListMask(); + uint32_t numDrawPackets = 0; + uint32_t numVisibleCullables = 0; - const View::UsageFlags viewFlags = m_jobData->m_view->GetUsageFlags(); - const RHI::DrawListMask drawListMask = m_jobData->m_view->GetDrawListMask(); - uint32_t numDrawPackets = 0; - uint32_t numVisibleCullables = 0; + AZ_Assert(worklist.size() > 0, "Received empty worklist in ProcessWorklist"); - for (const AzFramework::IVisibilityScene::NodeData& nodeData : m_worklist) - { - //If a node is entirely contained within the frustum, then we can skip the fine grained culling. - bool nodeIsContainedInFrustum = ShapeIntersection::Contains(m_jobData->m_frustum, nodeData.m_bounds); + for (const AzFramework::IVisibilityScene::NodeData& nodeData : worklist) + { + //If a node is entirely contained within the frustum, then we can skip the fine grained culling. + bool nodeIsContainedInFrustum = ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds); #ifdef AZ_CULL_PROFILE_VERBOSE - AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %d", - m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0); + AZ_PROFILE_SCOPE(RPI, "process node (view: %s, skip fine cull: %d", + m_view->GetName().GetCStr(), nodeIsContainedInFrustum ? 1 : 0); #endif - if (nodeIsContainedInFrustum || !m_jobData->m_debugCtx->m_enableFrustumCulling) - { - //Add all objects within this node to the view, without any extra culling - for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) - { - { - if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) - { - Cullable* c = static_cast(visibleEntry->m_userData); - - if ((c->m_cullData.m_drawListMask & drawListMask).none() || - c->m_cullData.m_hideFlags & viewFlags || - c->m_cullData.m_scene != m_jobData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this - c->m_isHidden) - { - continue; - } - -#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) -#endif - { - numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); - ++numVisibleCullables; - c->m_isVisible = true; - } - } - } - } - } - else + if (nodeIsContainedInFrustum || !worklistData->m_debugCtx->m_enableFrustumCulling) + { + //Add all objects within this node to the view, without any extra culling + for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { - //Do fine-grained culling before adding objects to the view - for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { @@ -355,160 +339,188 @@ namespace AZ if ((c->m_cullData.m_drawListMask & drawListMask).none() || c->m_cullData.m_hideFlags & viewFlags || - c->m_cullData.m_scene != m_jobData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this + c->m_cullData.m_scene != worklistData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this c->m_isHidden) { continue; } - IntersectResult res = ShapeIntersection::Classify(m_jobData->m_frustum, c->m_cullData.m_boundingSphere); - if (res == IntersectResult::Exterior) - { - continue; - } - else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(m_jobData->m_frustum, c->m_cullData.m_boundingObb)) - { #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - if (TestOcclusionCulling(visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) + if (TestOcclusionCulling(worklistData, visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) #endif - { - numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); - ++numVisibleCullables; - c->m_isVisible = true; - } + { + numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *worklistData->m_view); + ++numVisibleCullables; + c->m_isVisible = true; } } } } - - if (m_jobData->m_debugCtx->m_debugDraw && (m_jobData->m_view->GetName() == m_jobData->m_debugCtx->m_currentViewSelectionName)) + } + else + { + //Do fine-grained culling before adding objects to the view + for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { - AZ_PROFILE_SCOPE(RPI, "debug draw culling"); - - AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_jobData->m_scene); - if (auxGeomPtr) + if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { - //Draw the node bounds - // "Fully visible" nodes are nodes that are fully inside the frustum. "Partially visible" nodes intersect the edges of the frustum. - // Since the nodes of an octree have lots of overlapping boxes with coplanar edges, it's easier to view these separately, so - // we have a few debug booleans to toggle which ones to draw. - if (nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawFullyVisibleNodes) + Cullable* c = static_cast(visibleEntry->m_userData); + + if ((c->m_cullData.m_drawListMask & drawListMask).none() || + c->m_cullData.m_hideFlags & viewFlags || + c->m_cullData.m_scene != worklistData->m_scene || //[GFX_TODO][ATOM-13796] once the IVisibilitySystem supports multiple octree scenes, remove this + c->m_isHidden) { - auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Lime, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off); + continue; } - else if (!nodeIsContainedInFrustum && m_jobData->m_debugCtx->m_drawPartiallyVisibleNodes) + + IntersectResult res = ShapeIntersection::Classify(worklistData->m_frustum, c->m_cullData.m_boundingSphere); + if (res == IntersectResult::Exterior) { - auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Yellow, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off); + continue; + } + else if (res == IntersectResult::Interior || ShapeIntersection::Overlaps(worklistData->m_frustum, c->m_cullData.m_boundingObb)) + { +#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED + if (TestOcclusionCulling(worklistData, visibleEntry) == MaskedOcclusionCulling::CullingResult::VISIBLE) +#endif + { + numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *worklistData->m_view); + ++numVisibleCullables; + c->m_isVisible = true; + } } + } + } + } + + if (worklistData->m_debugCtx->m_debugDraw && (worklistData->m_view->GetName() == worklistData->m_debugCtx->m_currentViewSelectionName)) + { + AZ_PROFILE_SCOPE(RPI, "debug draw culling"); + + AuxGeomDrawPtr auxGeomPtr = AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(worklistData->m_scene); + if (auxGeomPtr) + { + //Draw the node bounds + // "Fully visible" nodes are nodes that are fully inside the frustum. "Partially visible" nodes intersect the edges of the frustum. + // Since the nodes of an octree have lots of overlapping boxes with coplanar edges, it's easier to view these separately, so + // we have a few debug booleans to toggle which ones to draw. + if (nodeIsContainedInFrustum && worklistData->m_debugCtx->m_drawFullyVisibleNodes) + { + auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Lime, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off); + } + else if (!nodeIsContainedInFrustum && worklistData->m_debugCtx->m_drawPartiallyVisibleNodes) + { + auxGeomPtr->DrawAabb(nodeData.m_bounds, Colors::Yellow, RPI::AuxGeomDraw::DrawStyle::Line, RPI::AuxGeomDraw::DepthTest::Off); + } - //Draw bounds on individual objects - if (m_jobData->m_debugCtx->m_drawBoundingBoxes || m_jobData->m_debugCtx->m_drawBoundingSpheres || m_jobData->m_debugCtx->m_drawLodRadii) + //Draw bounds on individual objects + if (worklistData->m_debugCtx->m_drawBoundingBoxes || worklistData->m_debugCtx->m_drawBoundingSpheres || worklistData->m_debugCtx->m_drawLodRadii) + { + for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) { - for (AzFramework::VisibilityEntry* visibleEntry : nodeData.m_entries) + if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) { - if (visibleEntry->m_typeFlags & AzFramework::VisibilityEntry::TYPE_RPI_Cullable) + Cullable* c = static_cast(visibleEntry->m_userData); + if (worklistData->m_debugCtx->m_drawBoundingBoxes) { - Cullable* c = static_cast(visibleEntry->m_userData); - if (m_jobData->m_debugCtx->m_drawBoundingBoxes) - { - auxGeomPtr->DrawObb(c->m_cullData.m_boundingObb, Matrix3x4::Identity(), - nodeIsContainedInFrustum ? Colors::Lime : Colors::Yellow, AuxGeomDraw::DrawStyle::Line); - } - - if (m_jobData->m_debugCtx->m_drawBoundingSpheres) - { - auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_cullData.m_boundingSphere.GetRadius(), - Color(0.5f, 0.5f, 0.5f, 0.3f), AuxGeomDraw::DrawStyle::Shaded); - } - - if (m_jobData->m_debugCtx->m_drawLodRadii) - { - auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), - c->m_lodData.m_lodSelectionRadius, - Color(1.0f, 0.5f, 0.0f, 0.3f), RPI::AuxGeomDraw::DrawStyle::Shaded); - } + auxGeomPtr->DrawObb(c->m_cullData.m_boundingObb, Matrix3x4::Identity(), + nodeIsContainedInFrustum ? Colors::Lime : Colors::Yellow, AuxGeomDraw::DrawStyle::Line); + } + + if (worklistData->m_debugCtx->m_drawBoundingSpheres) + { + auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), c->m_cullData.m_boundingSphere.GetRadius(), + Color(0.5f, 0.5f, 0.5f, 0.3f), AuxGeomDraw::DrawStyle::Shaded); + } + + if (worklistData->m_debugCtx->m_drawLodRadii) + { + auxGeomPtr->DrawSphere(c->m_cullData.m_boundingSphere.GetCenter(), + c->m_lodData.m_lodSelectionRadius, + Color(1.0f, 0.5f, 0.0f, 0.3f), RPI::AuxGeomDraw::DrawStyle::Shaded); } } } } } } + } - if (m_jobData->m_debugCtx->m_enableStats) - { - CullingDebugContext::CullStats& cullStats = m_jobData->m_debugCtx->GetCullStatsForView(m_jobData->m_view); + if (worklistData->m_debugCtx->m_enableStats) + { + CullingDebugContext::CullStats& cullStats = worklistData->m_debugCtx->GetCullStatsForView(worklistData->m_view); - //no need for mutex here since these are all atomics - cullStats.m_numVisibleDrawPackets += numDrawPackets; - cullStats.m_numVisibleCullables += numVisibleCullables; - ++cullStats.m_numJobs; - } + //no need for mutex here since these are all atomics + cullStats.m_numVisibleDrawPackets += numDrawPackets; + cullStats.m_numVisibleCullables += numVisibleCullables; + ++cullStats.m_numJobs; } + } #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - MaskedOcclusionCulling::CullingResult TestOcclusionCulling(AzFramework::VisibilityEntry* visibleEntry) + static MaskedOcclusionCulling::CullingResult TestOcclusionCulling( + const AZStd::shared_ptr& worklistData, + AzFramework::VisibilityEntry* visibleEntry) + { + if (!worklistData->m_maskedOcclusionCulling) { - if (!m_jobData->m_maskedOcclusionCulling) - { - return MaskedOcclusionCulling::CullingResult::VISIBLE; - } + return MaskedOcclusionCulling::CullingResult::VISIBLE; + } - if (visibleEntry->m_boundingVolume.Contains(m_jobData->m_view->GetCameraTransform().GetTranslation())) + if (visibleEntry->m_boundingVolume.Contains(worklistData->m_view->GetCameraTransform().GetTranslation())) + { + // camera is inside bounding volume + return MaskedOcclusionCulling::CullingResult::VISIBLE; + } + + const Vector3& minBound = visibleEntry->m_boundingVolume.GetMin(); + const Vector3& maxBound = visibleEntry->m_boundingVolume.GetMax(); + + // compute bounding volume corners + Vector4 corners[8]; + corners[0] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f); + corners[1] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f); + corners[2] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f); + corners[3] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f); + corners[4] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); + corners[5] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f); + corners[6] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f); + corners[7] = worklistData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); + + // find min clip-space depth and NDC min/max + float minDepth = FLT_MAX; + float ndcMinX = FLT_MAX; + float ndcMinY = FLT_MAX; + float ndcMaxX = -FLT_MAX; + float ndcMaxY = -FLT_MAX; + for (uint32_t index = 0; index < 8; ++index) + { + minDepth = AZStd::min(minDepth, corners[index].GetW()); + if (minDepth < 0.00000001f) { - // camera is inside bounding volume return MaskedOcclusionCulling::CullingResult::VISIBLE; } - const Vector3& minBound = visibleEntry->m_boundingVolume.GetMin(); - const Vector3& maxBound = visibleEntry->m_boundingVolume.GetMax(); - - // compute bounding volume corners - Vector4 corners[8]; - corners[0] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f); - corners[1] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f); - corners[2] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), maxBound.GetZ(), 1.0f); - corners[3] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), minBound.GetY(), minBound.GetZ(), 1.0f); - corners[4] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); - corners[5] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(minBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f); - corners[6] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), maxBound.GetZ(), 1.0f); - corners[7] = m_jobData->m_view->GetWorldToClipMatrix() * Vector4(maxBound.GetX(), maxBound.GetY(), minBound.GetZ(), 1.0f); - - // find min clip-space depth and NDC min/max - float minDepth = FLT_MAX; - float ndcMinX = FLT_MAX; - float ndcMinY = FLT_MAX; - float ndcMaxX = -FLT_MAX; - float ndcMaxY = -FLT_MAX; - for (uint32_t index = 0; index < 8; ++index) - { - minDepth = AZStd::min(minDepth, corners[index].GetW()); - - // convert to NDC - corners[index] /= corners[index].GetW(); - ndcMinX = AZStd::min(ndcMinX, corners[index].GetX()); - ndcMinY = AZStd::min(ndcMinY, corners[index].GetY()); - ndcMaxX = AZStd::max(ndcMaxX, corners[index].GetX()); - ndcMaxY = AZStd::max(ndcMaxY, corners[index].GetY()); - } + // convert to NDC + corners[index] /= corners[index].GetW(); - if (minDepth < 0.00000001f) - { - return MaskedOcclusionCulling::VISIBLE; - } - - // test against the occlusion buffer, which contains only the manually placed occlusion planes - return m_jobData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth); + ndcMinX = AZStd::min(ndcMinX, corners[index].GetX()); + ndcMinY = AZStd::min(ndcMinY, corners[index].GetY()); + ndcMaxX = AZStd::max(ndcMaxX, corners[index].GetX()); + ndcMaxY = AZStd::max(ndcMaxY, corners[index].GetY()); } + + // test against the occlusion buffer, which contains only the manually placed occlusion planes + return worklistData->m_maskedOcclusionCulling->TestRect(ndcMinX, ndcMinY, ndcMaxX, ndcMaxY, minDepth); + } #endif - }; - void CullingScene::ProcessCullables(const Scene& scene, View& view, AZ::Job& parentJob) + void CullingScene::ProcessCullablesCommon(const Scene& scene, View& view, AZ::Frustum& frustum, void*& maskedOcclusionCulling) { - AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullables() - %s", view.GetName().GetCStr()); + AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesCommon() - %s", view.GetName().GetCStr()); - const Matrix4x4& worldToClip = view.GetWorldToClipMatrix(); - Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip); if (m_debugCtx.m_freezeFrustums) { AZStd::lock_guard lock(m_debugCtx.m_frozenFrustumsMutex); @@ -536,7 +548,7 @@ namespace AZ #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED // setup occlusion culling, if necessary - MaskedOcclusionCulling* maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); + maskedOcclusionCulling = m_occlusionPlanes.empty() ? nullptr : view.GetMaskedOcclusionCulling(); if (maskedOcclusionCulling) { // frustum cull occlusion planes @@ -578,23 +590,27 @@ namespace AZ static uint32_t indices[6] = { 0, 1, 2, 2, 3, 0 }; // render into the occlusion buffer, specifying BACKFACE_NONE so it functions as a double-sided occluder - maskedOcclusionCulling->RenderTriangles((float*)verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE); + static_cast(maskedOcclusionCulling)->RenderTriangles(verts, indices, 2, nullptr, MaskedOcclusionCulling::BACKFACE_NONE); } } #endif + } + + void CullingScene::ProcessCullablesJobs(const Scene& scene, View& view, AZ::Job& parentJob) + { + AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesJobs() - %s", view.GetName().GetCStr()); + + const Matrix4x4& worldToClip = view.GetWorldToClipMatrix(); + AZ::Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip); + + void* maskedOcclusionCulling = nullptr; + ProcessCullablesCommon(scene, view, frustum, maskedOcclusionCulling); WorkListType worklist; - AZStd::shared_ptr jobData = AZStd::make_shared(); - jobData->m_debugCtx = &m_debugCtx; - jobData->m_scene = &scene; - jobData->m_view = &view; - jobData->m_frustum = frustum; -#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - jobData->m_maskedOcclusionCulling = maskedOcclusionCulling; -#endif + AZStd::shared_ptr worklistData = MakeWorklistData(m_debugCtx, scene, view, frustum, maskedOcclusionCulling); - auto nodeVisitorLambda = [jobData, &parentJob, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void + auto nodeVisitorLambda = [worklistData, &parentJob, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void { AZ_PROFILE_SCOPE(RPI, "nodeVisitorLambda()"); AZ_Assert(nodeData.m_entries.size() > 0, "should not get called with 0 entries"); @@ -606,8 +622,13 @@ namespace AZ if (worklist.size() == worklist.capacity()) { + // capture worklistData & worklist by value + auto processWorklist = [worklistData, worklist]() + { + ProcessWorklist(worklistData, worklist); + }; //Kick off a job to process the (full) worklist - AddObjectsToViewJob* job = aznew AddObjectsToViewJob(jobData, worklist); //pool allocated (cheap), auto-deletes when job finishes + AZ::Job* job = AZ::CreateJobFunction(processWorklist, true); worklist.clear(); parentJob.SetContinuation(job); job->Start(); @@ -616,7 +637,7 @@ namespace AZ if (m_debugCtx.m_enableFrustumCulling) { - m_visScene->Enumerate(frustum, nodeVisitorLambda); + m_visScene->Enumerate(frustum, nodeVisitorLambda); } else { @@ -625,21 +646,76 @@ namespace AZ if (worklist.size() > 0) { - AZStd::shared_ptr remainingJobData = AZStd::make_shared(); - remainingJobData->m_debugCtx = &m_debugCtx; - remainingJobData->m_scene = &scene; - remainingJobData->m_view = &view; - remainingJobData->m_frustum = frustum; -#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED - remainingJobData->m_maskedOcclusionCulling = maskedOcclusionCulling; -#endif - //Kick off a job to process any remaining workitems - AddObjectsToViewJob* job = aznew AddObjectsToViewJob(remainingJobData, worklist); //pool allocated (cheap), auto-deletes when job finishes + // capture worklistData & worklist by value + auto processWorklist = [worklistData, worklist]() + { + ProcessWorklist(worklistData, worklist); + }; + //Kick off a job to process the (full) worklist + AZ::Job* job = AZ::CreateJobFunction(processWorklist, true); parentJob.SetContinuation(job); job->Start(); } } + void CullingScene::ProcessCullablesTG(const Scene& scene, View& view, AZ::TaskGraph& taskGraph) + { + AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesTG() - %s", view.GetName().GetCStr()); + + const Matrix4x4& worldToClip = view.GetWorldToClipMatrix(); + AZ::Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip); + + void* maskedOcclusionCulling = nullptr; + ProcessCullablesCommon(scene, view, frustum, maskedOcclusionCulling); + + AZStd::unique_ptr worklist = AZStd::make_unique(); + + AZStd::shared_ptr worklistData = MakeWorklistData(m_debugCtx, scene, view, frustum, maskedOcclusionCulling); + static const AZ::TaskDescriptor descriptor{ "AZ::RPI::ProcessWorklist", "Graphics" }; + + auto nodeVisitorLambda = [worklistData, &taskGraph, &worklist](const AzFramework::IVisibilityScene::NodeData& nodeData) -> void + { + AZ_PROFILE_SCOPE(RPI, "nodeVisitorLambda()"); + AZ_Assert(nodeData.m_entries.size() > 0, "should not get called with 0 entries"); + AZ_Assert(worklist->size() < worklist->capacity(), "we should always have room to push a node on the queue"); + + //Queue up a small list of work items (NodeData*) which will be pushed to a worker task once the queue is full. + //This reduces the number of tasks in flight, reducing task-system overhead. + worklist->emplace_back(AZStd::move(nodeData)); + + if (worklist->size() == worklist->capacity()) + { + //Task takes ownership of the worklist unique ptr + taskGraph.AddTask( descriptor, [worklistData, worklist = AZStd::move(worklist)]() + { + ProcessWorklist(worklistData, *worklist.get()); + // allow worklist to go out of scope and be deleted + }); + worklist = AZStd::make_unique(); + } + }; + + if (m_debugCtx.m_enableFrustumCulling) + { + m_visScene->Enumerate(frustum, nodeVisitorLambda); + } + else + { + m_visScene->EnumerateNoCull(nodeVisitorLambda); + } + + if (worklist->size() > 0) + { + //Task takes ownership of the worklist unique ptr + taskGraph.AddTask( descriptor, [worklistData, worklist = AZStd::move(worklist)]() + { + ProcessWorklist(worklistData, *worklist.get()); + // allow worklist to go out of scope and be deleted + }); + } + } + + uint32_t AddLodDataToView(const Vector3& pos, const Cullable::LodData& lodData, RPI::View& view) { #ifdef AZ_CULL_PROFILE_DETAILED @@ -702,6 +778,8 @@ namespace AZ AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", m_parentScene->GetName().GetCStr())); m_visScene = AZ::Interface::Get()->CreateVisibilityScene(visSceneName); + m_taskGraphActive = AZ::Interface::Get(); + #ifdef AZ_CULL_DEBUG_ENABLED AZ_Assert(CountObjectsInScene() == 0, "The culling system should start with 0 entries in this scene."); #endif @@ -719,13 +797,27 @@ namespace AZ } } - void CullingScene::BeginCulling(const AZStd::vector& views) + void CullingScene::BeginCullingTaskGraph(const AZStd::vector& views) { - AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCulling"); - m_cullDataConcurrencyCheck.soft_lock(); + AZ::TaskGraph taskGraph; + AZ::TaskDescriptor beginCullingDescriptor{"RPI_CullingScene_BeginCullingView", "Graphics"}; + for (auto& view : views) + { + taskGraph.AddTask( + beginCullingDescriptor, + [&view]() + { + view->BeginCulling(); + }); + } - m_debugCtx.ResetCullStats(); - m_debugCtx.m_numCullablesInScene = GetNumCullables(); + AZ::TaskGraphEvent waitForCompletion; + taskGraph.Submit(&waitForCompletion); + waitForCompletion.Wait(); + } + + void CullingScene::BeginCullingJobs(const AZStd::vector& views) + { AZ::JobCompletion beginCullingCompletion; for (auto& view : views) @@ -741,6 +833,26 @@ namespace AZ } beginCullingCompletion.StartAndWaitForCompletion(); + } + + void CullingScene::BeginCulling(const AZStd::vector& views) + { + AZ_PROFILE_SCOPE(RPI, "CullingScene: BeginCulling"); + m_cullDataConcurrencyCheck.soft_lock(); + + m_debugCtx.ResetCullStats(); + m_debugCtx.m_numCullablesInScene = GetNumCullables(); + + m_taskGraphActive = AZ::Interface::Get(); + + if (m_taskGraphActive && m_taskGraphActive->IsTaskGraphActive()) + { + BeginCullingTaskGraph(views); + } + else + { + BeginCullingJobs(views); + } AuxGeomDrawPtr auxGeom; if (m_debugCtx.m_debugDraw) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 41fefda656..8ec968943d 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -111,7 +111,7 @@ namespace AZ { if (m_taskGraphActive) { - WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + WaitAndCleanTGEvent(AZStd::move(m_simulationFinishedTGEvent)); } else { @@ -385,8 +385,8 @@ namespace AZ }); } simulationTG.Detach(); - m_simulationFinishedWorkActive = true; - simulationTG.Submit(&m_simulationFinishedTGEvent); + m_simulationFinishedTGEvent = AZStd::make_unique(); + simulationTG.Submit(m_simulationFinishedTGEvent.get()); } void Scene::SimulateJobs() @@ -419,7 +419,7 @@ namespace AZ // If previous simulation job wasn't done, wait for it to finish. if (m_taskGraphActive) { - WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + WaitAndCleanTGEvent(AZStd::move(m_simulationFinishedTGEvent)); } else { @@ -449,17 +449,14 @@ namespace AZ } } - void Scene::WaitTGEvent(AZ::TaskGraphEvent& completionTGEvent, AZStd::atomic_bool* workToWaitOn ) + void Scene::WaitAndCleanTGEvent(AZStd::unique_ptr&& completionTGEvent) { - AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanCompletionJob"); - if (!workToWaitOn || workToWaitOn->load()) + AZ_PROFILE_SCOPE(RPI, "Scene: WaitAndCleanTGEvent"); + if (completionTGEvent) { - completionTGEvent.Wait(); - } - if (workToWaitOn) - { - workToWaitOn->store(false); + completionTGEvent->Wait(); } + // allow completionTGEvent to go out of scope and be deleted } void Scene::WaitAndCleanCompletionJob(AZ::JobCompletion*& completionJob) @@ -499,12 +496,12 @@ namespace AZ void Scene::CollectDrawPacketsTaskGraph() { - AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); + AZ_PROFILE_SCOPE(RPI, "CollectDrawPacketsTaskGraph"); AZ::TaskGraphEvent collectDrawPacketsTGEvent; static const AZ::TaskDescriptor collectDrawPacketsTGDesc{"RPI_Scene_PrepareRender_CollectDrawPackets", "Graphics"}; - AZ::TaskGraph collectDrawPacketsTG; - // Launch FeatureProcessor::Render() jobs + + // Launch FeatureProcessor::Render() taskgraphs for (auto& fp : m_featureProcessors) { collectDrawPacketsTG.AddTask( @@ -520,32 +517,48 @@ namespace AZ // Launch CullingSystem::ProcessCullables() jobs (will run concurrently with FeatureProcessor::Render() jobs if m_parallelOctreeTraversal) bool parallelOctreeTraversal = m_cullingScene->GetDebugContext().m_parallelOctreeTraversal; m_cullingScene->BeginCulling(m_renderPacket.m_views); - AZ::JobCompletion processCullablesCompletion; - for (ViewPtr& viewPtr : m_renderPacket.m_views) + static const AZ::TaskDescriptor processCullablesDescriptor{"AZ::RPI::Scene::ProcessCullables", "Graphics"}; + AZ::TaskGraphEvent processCullablesTGEvent; + AZ::TaskGraph processCullablesTG; + if (parallelOctreeTraversal) { - AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) - { - m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job - }, - true, nullptr); //auto-deletes - if (parallelOctreeTraversal) + for (ViewPtr& viewPtr : m_renderPacket.m_views) { - processCullablesJob->SetDependent(&processCullablesCompletion); - processCullablesJob->Start(); + processCullablesTG.AddTask(processCullablesDescriptor, [this, &viewPtr, &processCullablesTGEvent]() + { + AZ::TaskGraph subTaskGraph; + m_cullingScene->ProcessCullablesTG(*this, *viewPtr, subTaskGraph); + if (!subTaskGraph.IsEmpty()) + { + subTaskGraph.Detach(); + subTaskGraph.Submit(&processCullablesTGEvent); + } + }); } - else + } + else + { + for (ViewPtr& viewPtr : m_renderPacket.m_views) { - processCullablesJob->StartAndWaitForCompletion(); + m_cullingScene->ProcessCullablesTG(*this, *viewPtr, processCullablesTG); } } + bool processCullablesHasWork = !processCullablesTG.IsEmpty(); + if (processCullablesHasWork) + { + processCullablesTG.Submit(&processCullablesTGEvent); + } - WaitTGEvent(collectDrawPacketsTGEvent); - processCullablesCompletion.StartAndWaitForCompletion(); + collectDrawPacketsTGEvent.Wait(); + if (processCullablesHasWork) // skip the wait if there is no work to do + { + processCullablesTGEvent.Wait(); + } } void Scene::CollectDrawPacketsJobs() { - AZ_PROFILE_SCOPE(RPI, "CollectDrawPackets"); + AZ_PROFILE_SCOPE(RPI, "CollectDrawPacketsJobs"); AZ::JobCompletion* collectDrawPacketsCompletion = aznew AZ::JobCompletion(); // Launch FeatureProcessor::Render() jobs @@ -567,7 +580,7 @@ namespace AZ { AZ::Job* processCullablesJob = AZ::CreateJobFunction([this, &viewPtr](AZ::Job& thisJob) { - m_cullingScene->ProcessCullables(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job + m_cullingScene->ProcessCullablesJobs(*this, *viewPtr, thisJob); // can't call directly because ProcessCullables needs a parent job }, true, nullptr); //auto-deletes if (m_cullingScene->GetDebugContext().m_parallelOctreeTraversal) @@ -600,7 +613,7 @@ namespace AZ }); } finalizeDrawListsTG.Submit(&finalizeDrawListsTGEvent); - WaitTGEvent(finalizeDrawListsTGEvent); + finalizeDrawListsTGEvent.Wait(); } void Scene::FinalizeDrawListsJobs() @@ -626,7 +639,7 @@ namespace AZ if (m_taskGraphActive) { - WaitTGEvent(m_simulationFinishedTGEvent, &m_simulationFinishedWorkActive); + WaitAndCleanTGEvent(AZStd::move(m_simulationFinishedTGEvent)); } else { From 9dc85000a3ec1a6c6633d718f5c455ab11a46818 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 2 Nov 2021 13:21:51 -0700 Subject: [PATCH 152/200] LYN-7547 | Focus Mode - It is possible to create a child entity of a closed container (#5193) * Disable drag&drop of entities on closed containers. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Do not show the Create Entity context menu when right clicking a closed prefab container. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Disable entity creation on closed containers, both via the Create Entity flow and drag/drop of assets. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Minor changes to modernize old code. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../SandboxIntegration.cpp | 26 +++++++++------ .../Prefab/PrefabPublicHandler.cpp | 12 ++++++- .../UI/Outliner/EntityOutlinerListModel.cpp | 33 ++++++++++++++++--- 3 files changed, 56 insertions(+), 15 deletions(-) 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/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/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) From 3466e5120653eb2d754ea1ad3e58f9bc6989991c Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Tue, 2 Nov 2021 13:36:44 -0700 Subject: [PATCH 153/200] fixing formatting issues Signed-off-by: Neil Widmaier --- ...orComponents_OcclusionCullingPlaneAdded.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py index 26bff5a289..13009bb144 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py @@ -12,10 +12,10 @@ class Tests: creation_redo = ( "REDO Entity creation success", "REDO Entity creation failed") - Occlusion_Culling_Plane_entity_creation = ( + occlusion_culling_plane_entity_creation = ( "Occlusion Culling Plane Entity successfully created", "Occlusion Culling Plane Entity failed to be created") - Occlusion_Culling_Plane_component_added = ( + occlusion_culling_plane_component_added = ( "Entity has a Occlusion Culling Plane component", "Entity failed to find Occlusion Culling Plane component") enter_game_mode = ( @@ -41,10 +41,10 @@ class Tests: "REDO deletion failed") -def AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity(): +def AtomEditorComponents_occlusion_culling_plane_AddedToEntity(): """ Summary: - Tests the Occlusion_Culling_Plane component can be added to an entity and has the expected functionality. + Tests the occlusion_culling_plane component can be added to an entity and has the expected functionality. Test setup: - Wait for Editor idle loop. @@ -83,14 +83,17 @@ def AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity(): TestHelper.open_level("", "Base") # Test steps begin. - # 1. Create a Occlusion_Culling_Plane entity with no components. - occlusion_culling_plane_entity = EditorEntity.create_editor_entity(AtomComponentProperties.occlusion_culling_plane()) - Report.critical_result(Tests.Occlusion_Culling_Plane_entity_creation, occlusion_culling_plane_entity.exists()) - - # 2. Add a Occlusion_Culling_Plane component to Occlusion_Culling_Plane entity. - Occlusion_Culling_Plane_component = occlusion_culling_plane_entity.add_component(AtomComponentProperties.occlusion_culling_plane()) + # 1. Create a occlusion culling plane entity with no components. + occlusion_culling_plane_entity = EditorEntity.\ + create_editor_entity(AtomComponentProperties.occlusion_culling_plane()) + Report.critical_result(Tests.occlusion_culling_plane_entity_creation, + occlusion_culling_plane_entity.exists()) + + # 2. Add a occlusion culling plane component to occlusion culling plane entity. + occlusion_culling_plane_component = occlusion_culling_plane_entity.\ + add_component(AtomComponentProperties.occlusion_culling_plane()) Report.critical_result( - Tests.Occlusion_Culling_Plane_component_added, + Tests.occlusion_culling_plane_component_added, occlusion_culling_plane_entity.has_component(AtomComponentProperties.occlusion_culling_plane())) # 3. UNDO the entity creation and component addition. @@ -131,7 +134,7 @@ def AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.is_visible, occlusion_culling_plane_entity.is_visible() is True) - # 8. Delete Occlusion_Culling_Plane entity. + # 8. Delete occlusion_culling_plane entity. occlusion_culling_plane_entity.delete() Report.result(Tests.entity_deleted, not occlusion_culling_plane_entity.exists()) @@ -153,4 +156,4 @@ def AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity(): if __name__ == "__main__": from editor_python_test_tools.utils import Report - Report.start_test(AtomEditorComponents_Occlusion_Culling_Plane_AddedToEntity) + Report.start_test(AtomEditorComponents_occlusion_culling_plane_AddedToEntity) From 36b6aed2dff673df04f670f8b7241ef417714d14 Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Tue, 2 Nov 2021 15:21:50 -0700 Subject: [PATCH 154/200] fixing function name formatting issues Signed-off-by: Neil Widmaier --- ...hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py index 13009bb144..e3ca911bdf 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py @@ -41,10 +41,10 @@ class Tests: "REDO deletion failed") -def AtomEditorComponents_occlusion_culling_plane_AddedToEntity(): +def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity(): """ Summary: - Tests the occlusion_culling_plane component can be added to an entity and has the expected functionality. + Tests the occlusion culling plane component can be added to an entity and has the expected functionality. Test setup: - Wait for Editor idle loop. @@ -156,4 +156,4 @@ def AtomEditorComponents_occlusion_culling_plane_AddedToEntity(): if __name__ == "__main__": from editor_python_test_tools.utils import Report - Report.start_test(AtomEditorComponents_occlusion_culling_plane_AddedToEntity) + Report.start_test(AtomEditorComponents_OcclusionCullingPlane_AddedToEntity) From 958c4c79200c757f7956e0524012d5df936ecdec Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 2 Nov 2021 15:13:18 -0700 Subject: [PATCH 155/200] Cherry-picked c9f4600bf38c1d422453fa079a88c973fcbe2bc7 Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 58 ++++++++++++++++------ cmake/install/Findo3de.cmake.in | 10 +++- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 2960a99c64..1f50175f98 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -477,26 +477,52 @@ function(ly_setup_cmake_install) COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - # Findo3de.cmake file: we generate a different Findo3de.camke file than the one we have in cmake. This one is going to expose all - # targets that are pre-built - unset(FIND_PACKAGES_PLACEHOLDER) + # Findo3de.cmake file: we generate a different Findo3de.cmake file than the one we have in the source dir. + configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) + ly_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" + DESTINATION cmake + COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + ) - # Add to the FIND_PACKAGES_PLACEHOLDER all directories in which ly_add_target were called in + unset(find_subdirectories) + # Add to find_subdirectories all directories in which ly_add_target were called in get_property(all_subdirectories GLOBAL PROPERTY LY_ALL_TARGET_DIRECTORIES) foreach(target_subdirectory IN LISTS all_subdirectories) cmake_path(RELATIVE_PATH target_subdirectory BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE relative_target_subdirectory) - string(APPEND FIND_PACKAGES_PLACEHOLDER " add_subdirectory(${relative_target_subdirectory})\n") + string(APPEND find_subdirectories "add_subdirectory(${relative_target_subdirectory})\n") endforeach() + set(permutation_find_subdirectories ${CMAKE_CURRENT_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + file(GENERATE OUTPUT ${permutation_find_subdirectories} + CONTENT +"# Generated by O3DE install\n +${find_subdirectories} +" + ) + ly_install(FILES "${permutation_find_subdirectories}" + DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} + ) - configure_file(${LY_ROOT_FOLDER}/cmake/install/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake @ONLY) - ly_install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/Findo3de.cmake" - DESTINATION cmake + set(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + file(GENERATE OUTPUT ${pal_builtin_file} + CONTENT +"# Generated by O3DE install\n +if(LY_MONOLITHIC_GAME) + include(cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/Monolithic/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +else() + include(cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/Default/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) +endif() +" + ) + ly_install(FILES "${pal_builtin_file}" + DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} ) - # BuiltInPackage_.cmake: since associations could happen in any cmake file across the engine. We collect - # all the associations in ly_associate_package and then generate them into BuiltInPackages_.cmake. This - # will consolidate all associations in one file + # ${LY_BUILD_PERMUTATION}/BuiltInPackage_.cmake: since associations could happen in any cmake file across the engine. We collect + # all the associations in ly_associate_package and then generate them into BuiltInPackages_.cmake. This will consolidate all + # associations in one file + # Associations are sensitive to platform and build permutation, so we make different files for each. get_property(all_package_names GLOBAL PROPERTY LY_PACKAGE_NAMES) list(REMOVE_DUPLICATES all_package_names) set(builtinpackages "# Generated by O3DE install\n\n") @@ -507,13 +533,13 @@ function(ly_setup_cmake_install) string(APPEND builtinpackages "ly_associate_package(PACKAGE_NAME ${package_name} TARGETS ${targets} PACKAGE_HASH ${package_hash})\n") endforeach() - set(pal_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) - file(GENERATE OUTPUT ${pal_builtin_file} + set(permutation_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + file(GENERATE OUTPUT ${permutation_builtin_file} CONTENT ${builtinpackages} ) - ly_install(FILES "${pal_builtin_file}" - DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} - COMPONENT ${CMAKE_INSTALL_DEFAULT_COMPONENT_NAME} + ly_install(FILES "${permutation_builtin_file}" + DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) endfunction() diff --git a/cmake/install/Findo3de.cmake.in b/cmake/install/Findo3de.cmake.in index e267b6b5c6..4239aa3b1e 100644 --- a/cmake/install/Findo3de.cmake.in +++ b/cmake/install/Findo3de.cmake.in @@ -12,7 +12,15 @@ include(FindPackageHandleStandardArgs) # This will be called from within the installed engine's CMakeLists.txt macro(ly_find_o3de_packages) -@FIND_PACKAGES_PLACEHOLDER@ + if(LY_MONOLITHIC_GAME) + set(monolithic_file "${LY_ROOT_FOLDER}/Platform/${PAL_PLATFORM_NAME}/Monolithic/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake") + if(NOT EXISTS ${monolithic_file}) + message(FATAL_ERROR "O3DE SDK was not generated to support monolithic builds") + endif() + include("${monolithic_file}") + else() + include("cmake/Platform/${PAL_PLATFORM_NAME}/Default/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake") + endif() find_package(LauncherGenerator) endmacro() From ebfb34733d4350d4591ae009512d2b0f8fa957d2 Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Tue, 2 Nov 2021 16:28:49 -0700 Subject: [PATCH 156/200] fixing new line formatting issues Signed-off-by: Neil Widmaier --- ...dra_AtomEditorComponents_OcclusionCullingPlaneAdded.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py index e3ca911bdf..4226ae3dfe 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py @@ -84,14 +84,14 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity(): # Test steps begin. # 1. Create a occlusion culling plane entity with no components. - occlusion_culling_plane_entity = EditorEntity.\ - create_editor_entity(AtomComponentProperties.occlusion_culling_plane()) + occlusion_culling_plane_entity = EditorEntity.create_editor_entity( + AtomComponentProperties.occlusion_culling_plane()) Report.critical_result(Tests.occlusion_culling_plane_entity_creation, occlusion_culling_plane_entity.exists()) # 2. Add a occlusion culling plane component to occlusion culling plane entity. - occlusion_culling_plane_component = occlusion_culling_plane_entity.\ - add_component(AtomComponentProperties.occlusion_culling_plane()) + occlusion_culling_plane_component = occlusion_culling_plane_entity.add_component( + AtomComponentProperties.occlusion_culling_plane()) Report.critical_result( Tests.occlusion_culling_plane_component_added, occlusion_culling_plane_entity.has_component(AtomComponentProperties.occlusion_culling_plane())) From c54331dee5f9779fd46e4338ff5b740343943a66 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 2 Nov 2021 16:36:02 -0700 Subject: [PATCH 157/200] Cherry-picked 3334f5eb91c8e973b02556ff833fc952536e8cdd Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/Platform/Common/Install_common.cmake | 4 ++-- cmake/install/Findo3de.cmake.in | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 1f50175f98..5e9f6ad0ce 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -533,12 +533,12 @@ endif() string(APPEND builtinpackages "ly_associate_package(PACKAGE_NAME ${package_name} TARGETS ${targets} PACKAGE_HASH ${package_hash})\n") endforeach() - set(permutation_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) + set(permutation_builtin_file ${CMAKE_CURRENT_BINARY_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) file(GENERATE OUTPUT ${permutation_builtin_file} CONTENT ${builtinpackages} ) ly_install(FILES "${permutation_builtin_file}" - DESTINATION cmake/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} + DESTINATION cmake/3rdParty/Platform/${PAL_PLATFORM_NAME}/${LY_BUILD_PERMUTATION} COMPONENT ${LY_INSTALL_PERMUTATION_COMPONENT} ) diff --git a/cmake/install/Findo3de.cmake.in b/cmake/install/Findo3de.cmake.in index 4239aa3b1e..12daf9df95 100644 --- a/cmake/install/Findo3de.cmake.in +++ b/cmake/install/Findo3de.cmake.in @@ -13,7 +13,7 @@ include(FindPackageHandleStandardArgs) # This will be called from within the installed engine's CMakeLists.txt macro(ly_find_o3de_packages) if(LY_MONOLITHIC_GAME) - set(monolithic_file "${LY_ROOT_FOLDER}/Platform/${PAL_PLATFORM_NAME}/Monolithic/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake") + set(monolithic_file "${LY_ROOT_FOLDER}/cmake/Platform/${PAL_PLATFORM_NAME}/Monolithic/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake") if(NOT EXISTS ${monolithic_file}) message(FATAL_ERROR "O3DE SDK was not generated to support monolithic builds") endif() From 458dad8e47aba40d29af0ff91d78a0e67ff89e75 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 2 Nov 2021 17:05:14 -0700 Subject: [PATCH 158/200] Making paths consistent (PR comment) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- cmake/install/Findo3de.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/install/Findo3de.cmake.in b/cmake/install/Findo3de.cmake.in index 12daf9df95..c3db7f1ec6 100644 --- a/cmake/install/Findo3de.cmake.in +++ b/cmake/install/Findo3de.cmake.in @@ -19,7 +19,7 @@ macro(ly_find_o3de_packages) endif() include("${monolithic_file}") else() - include("cmake/Platform/${PAL_PLATFORM_NAME}/Default/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake") + include("${LY_ROOT_FOLDER}/cmake/Platform/${PAL_PLATFORM_NAME}/Default/o3de_subdirectories_${PAL_PLATFORM_NAME_LOWERCASE}.cmake") endif() find_package(LauncherGenerator) endmacro() From 556847c93e94c516e5a4ca488f1c0305f6c7c109 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Tue, 2 Nov 2021 17:37:31 -0700 Subject: [PATCH 159/200] Adds LuaIDE->GridHub dependency Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Tools/GridHub/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Tools/GridHub/CMakeLists.txt b/Code/Tools/GridHub/CMakeLists.txt index 26d8b8e557..8603c1e477 100644 --- a/Code/Tools/GridHub/CMakeLists.txt +++ b/Code/Tools/GridHub/CMakeLists.txt @@ -35,3 +35,5 @@ ly_add_target( AZ::AzCore AZ::GridMate ) + +ly_add_dependencies(LuaIDE GridHub) From 0c86198fd9d0e840e74c62eba7a2f2846e9a43ed Mon Sep 17 00:00:00 2001 From: rhhong Date: Tue, 2 Nov 2021 23:09:42 -0700 Subject: [PATCH 160/200] CR feedback; add ability to update the render in the preference window. Signed-off-by: rhhong --- .../Code/Source/AtomActorDebugDraw.cpp | 93 +++++++++++-------- .../Code/Source/AtomActorDebugDraw.h | 22 ++++- .../EMotionFX/Source/EMotionFXManager.cpp | 12 +-- .../Code/EMotionFX/Source/EMotionFXManager.h | 14 +-- .../Source/RenderPlugin/RenderOptions.cpp | 14 ++- .../Rendering/RenderActorSettings.h | 4 + 6 files changed, 92 insertions(+), 67 deletions(-) diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp index 4b06fc5753..50af91020a 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp @@ -41,16 +41,18 @@ namespace AZ::Render return; } + const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); + // Render aabb if (renderFlags[EMotionFX::ActorRenderFlag::RENDER_AABB]) { - RenderAABB(instance); + RenderAABB(instance, renderActorSettings.m_staticAABBColor); } // Render skeleton if (renderFlags[EMotionFX::ActorRenderFlag::RENDER_LINESKELETON]) { - RenderSkeleton(instance); + RenderSkeleton(instance, renderActorSettings.m_skeletonColor); } // Render internal EMFX debug lines. @@ -85,14 +87,16 @@ namespace AZ::Render continue; } - RenderNormals(mesh, globalTM, renderVertexNormals, renderFaceNormals, scaleMultiplier); + RenderNormals(mesh, globalTM, renderVertexNormals, renderFaceNormals, renderActorSettings.m_vertexNormalsScale, + renderActorSettings.m_faceNormalsScale, scaleMultiplier, renderActorSettings.m_vertexNormalsColor, renderActorSettings.m_faceNormalsColor); if (renderTangents) { - RenderTangents(mesh, globalTM, scaleMultiplier); + RenderTangents(mesh, globalTM, renderActorSettings.m_tangentsScale, scaleMultiplier, + renderActorSettings.m_tangentsColor, renderActorSettings.m_mirroredBitangentsColor, renderActorSettings.m_bitangentsColor); } if (renderWireframe) { - RenderWireframe(mesh, globalTM, scaleMultiplier); + RenderWireframe(mesh, globalTM, renderActorSettings.m_wireframeScale, scaleMultiplier, renderActorSettings.m_wireframeColor); } } } @@ -101,8 +105,8 @@ namespace AZ::Render float AtomActorDebugDraw::CalculateScaleMultiplier(EMotionFX::ActorInstance* instance) const { const AZ::Aabb aabb = instance->GetAabb(); - const float aabbRadius = AZ::Vector3(aabb.GetMax() - aabb.GetMin()).GetLength() * 0.5f; - // Scale the multiplier down to 1% of the character size, that looks pretty nice on all models + const float aabbRadius = aabb.GetExtents().GetLength() * 0.5f; + // Scale the multiplier down to 1% of the character size, that looks pretty nice on most of the models. return aabbRadius * 0.01f; } @@ -134,15 +138,14 @@ namespace AZ::Render } } - void AtomActorDebugDraw::RenderAABB(EMotionFX::ActorInstance* instance) + void AtomActorDebugDraw::RenderAABB(EMotionFX::ActorInstance* instance, const AZ::Color& aabbColor) { RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); const AZ::Aabb& aabb = instance->GetAabb(); - const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); - auxGeom->DrawAabb(aabb, renderActorSettings.m_staticAABBColor, RPI::AuxGeomDraw::DrawStyle::Line); + auxGeom->DrawAabb(aabb, aabbColor, RPI::AuxGeomDraw::DrawStyle::Line); } - void AtomActorDebugDraw::RenderSkeleton(EMotionFX::ActorInstance* instance) + void AtomActorDebugDraw::RenderSkeleton(EMotionFX::ActorInstance* instance, const AZ::Color& skeletonColor) { RPI::AuxGeomDrawPtr auxGeom = m_auxGeomFeatureProcessor->GetDrawQueue(); @@ -177,11 +180,10 @@ namespace AZ::Render m_auxVertices.emplace_back(bonePos); } - const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &renderActorSettings.m_lineSkeletonColor; + lineArgs.m_colors = &skeletonColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); @@ -229,7 +231,16 @@ namespace AZ::Render auxGeom->DrawLines(lineArgs); } - void AtomActorDebugDraw::RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals, float scaleMultiplier) + void AtomActorDebugDraw::RenderNormals( + EMotionFX::Mesh* mesh, + const AZ::Transform& worldTM, + bool vertexNormals, + bool faceNormals, + float vertexNormalsScale, + float faceNormalsScale, + float scaleMultiplier, + const AZ::Color& vertexNormalsColor, + const AZ::Color& faceNormalsColor) { if (!mesh) { @@ -247,8 +258,6 @@ namespace AZ::Render return; } - const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); - PrepareForMesh(mesh, worldTM); AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); @@ -284,14 +293,14 @@ namespace AZ::Render const AZ::Vector3 normalPos = (posA + posB + posC) * (1.0f / 3.0f); m_auxVertices.emplace_back(normalPos); - m_auxVertices.emplace_back(normalPos + (normalDir * renderActorSettings.m_faceNormalsScale * scaleMultiplier)); + m_auxVertices.emplace_back(normalPos + (normalDir * faceNormalsScale * scaleMultiplier)); } } RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &renderActorSettings.m_faceNormalsColor; + lineArgs.m_colors = &faceNormalsColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); @@ -315,7 +324,7 @@ namespace AZ::Render const uint32 vertexIndex = j + startVertex; const AZ::Vector3& position = m_worldSpacePositions[vertexIndex]; const AZ::Vector3 normal = worldTM.TransformVector(normals[vertexIndex]).GetNormalizedSafe() * - renderActorSettings.m_vertexNormalsScale * scaleMultiplier; + vertexNormalsScale * scaleMultiplier; m_auxVertices.emplace_back(position); m_auxVertices.emplace_back(position + normal); @@ -325,14 +334,21 @@ namespace AZ::Render RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &renderActorSettings.m_vertexNormalsColor; + lineArgs.m_colors = &vertexNormalsColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); } } - void AtomActorDebugDraw::RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier) + void AtomActorDebugDraw::RenderTangents( + EMotionFX::Mesh* mesh, + const AZ::Transform& worldTM, + float tangentsScale, + float scaleMultiplier, + const AZ::Color& tangentsColor, + const AZ::Color& mirroredBitangentsColor, + const AZ::Color& bitangentsColor) { if (!mesh) { @@ -345,8 +361,6 @@ namespace AZ::Render return; } - const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); - // Get the tangents and check if this mesh actually has tangents AZ::Vector4* tangents = static_cast(mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_TANGENTS)); if (!tangents) @@ -384,23 +398,23 @@ namespace AZ::Render bitangent = (worldTM.TransformVector(bitangent)).GetNormalizedSafe(); m_auxVertices.emplace_back(m_worldSpacePositions[i]); - m_auxColors.emplace_back(renderActorSettings.m_tangentsColor); - m_auxVertices.emplace_back(m_worldSpacePositions[i] + (tangent * renderActorSettings.m_tangentsScale * scaleMultiplier)); - m_auxColors.emplace_back(renderActorSettings.m_tangentsColor); + m_auxColors.emplace_back(tangentsColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (tangent * tangentsScale * scaleMultiplier)); + m_auxColors.emplace_back(tangentsColor); if (tangents[i].GetW() < 0.0f) { m_auxVertices.emplace_back(m_worldSpacePositions[i]); - m_auxColors.emplace_back(renderActorSettings.m_mirroredBitangentsColor); - m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * renderActorSettings.m_tangentsScale * scaleMultiplier)); - m_auxColors.emplace_back(renderActorSettings.m_mirroredBitangentsColor); + m_auxColors.emplace_back(mirroredBitangentsColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * tangentsScale * scaleMultiplier)); + m_auxColors.emplace_back(mirroredBitangentsColor); } else { m_auxVertices.emplace_back(m_worldSpacePositions[i]); - m_auxColors.emplace_back(renderActorSettings.m_bitangentsColor); - m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * renderActorSettings.m_tangentsScale * scaleMultiplier)); - m_auxColors.emplace_back(renderActorSettings.m_bitangentsColor); + m_auxColors.emplace_back(bitangentsColor); + m_auxVertices.emplace_back(m_worldSpacePositions[i] + (bitangent * tangentsScale * scaleMultiplier)); + m_auxColors.emplace_back(bitangentsColor); } } @@ -413,7 +427,8 @@ namespace AZ::Render auxGeom->DrawLines(lineArgs); } - void AtomActorDebugDraw::RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier) + void AtomActorDebugDraw::RenderWireframe( + EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float wireframeScale, float scaleMultiplier, const AZ::Color& wireframeColor) { // Check if the mesh is valid and skip the node in case it's not if (!mesh) @@ -427,7 +442,6 @@ namespace AZ::Render return; } - const AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); PrepareForMesh(mesh, worldTM); const AZ::Vector3* normals = (AZ::Vector3*)mesh->FindVertexData(EMotionFX::Mesh::ATTRIB_NORMALS); @@ -450,12 +464,9 @@ namespace AZ::Render const uint32 indexB = indices[triangleStartIndex + 1] + startVertex; const uint32 indexC = indices[triangleStartIndex + 2] + startVertex; - const AZ::Vector3 posA = - m_worldSpacePositions[indexA] + normals[indexA] * renderActorSettings.m_wireframeScale * scaleMultiplier; - const AZ::Vector3 posB = - m_worldSpacePositions[indexB] + normals[indexB] * renderActorSettings.m_wireframeScale * scaleMultiplier; - const AZ::Vector3 posC = - m_worldSpacePositions[indexC] + normals[indexC] * renderActorSettings.m_wireframeScale * scaleMultiplier; + const AZ::Vector3 posA = m_worldSpacePositions[indexA] + normals[indexA] * wireframeScale * scaleMultiplier; + const AZ::Vector3 posB = m_worldSpacePositions[indexB] + normals[indexB] * wireframeScale * scaleMultiplier; + const AZ::Vector3 posC = m_worldSpacePositions[indexC] + normals[indexC] * wireframeScale * scaleMultiplier; m_auxVertices.emplace_back(posA); m_auxVertices.emplace_back(posB); @@ -470,7 +481,7 @@ namespace AZ::Render RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments lineArgs; lineArgs.m_verts = m_auxVertices.data(); lineArgs.m_vertCount = static_cast(m_auxVertices.size()); - lineArgs.m_colors = &renderActorSettings.m_wireframeColor; + lineArgs.m_colors = &wireframeColor; lineArgs.m_colorCount = 1; lineArgs.m_depthTest = RPI::AuxGeomDraw::DepthTest::Off; auxGeom->DrawLines(lineArgs); diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h index f674ffbb96..4178ad25f1 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h @@ -39,12 +39,24 @@ namespace AZ::Render float CalculateScaleMultiplier(EMotionFX::ActorInstance* instance) const; void PrepareForMesh(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM); - void RenderAABB(EMotionFX::ActorInstance* instance); - void RenderSkeleton(EMotionFX::ActorInstance* instance); + void RenderAABB(EMotionFX::ActorInstance* instance, const AZ::Color& aabbColor); + void RenderSkeleton(EMotionFX::ActorInstance* instance, const AZ::Color& skeletonColor); void RenderEMFXDebugDraw(EMotionFX::ActorInstance* instance); - void RenderNormals(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, bool vertexNormals, bool faceNormals, float scaleMultiplier); - void RenderTangents(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier); - void RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float scaleMultiplier); + void RenderNormals( + EMotionFX::Mesh* mesh, + const AZ::Transform& worldTM, + bool vertexNormals, + bool faceNormals, + float vertexNormalsScale, + float faceNormalsScale, + float scaleMultiplier, + const AZ::Color& vertexNormalsColor, + const AZ::Color& faceNormalsColor); + void RenderTangents( + EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float tangentsScale, float scaleMultiplier, + const AZ::Color& tangentsColor, const AZ::Color& mirroredBitangentsColor, const AZ::Color& bitangentsColor); + void RenderWireframe(EMotionFX::Mesh* mesh, const AZ::Transform& worldTM, float wireframeScale, float scaleMultiplier, + const AZ::Color& wireframeColor); EMotionFX::Mesh* m_currentMesh = nullptr; /**< A pointer to the mesh whose world space positions are in the pre-calculated positions buffer. NULL in case we haven't pre-calculated any positions yet. */ diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp index af041fd316..4ecd1c0117 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.cpp @@ -76,7 +76,6 @@ namespace EMotionFX gEMFX.Get()->SetRecorder (Recorder::Create()); gEMFX.Get()->SetMotionInstancePool (MotionInstancePool::Create()); gEMFX.Get()->SetDebugDraw (aznew DebugDraw()); - gEMFX.Get()->SetRenderActorSettings (new AZ::Render::RenderActorSettings()); gEMFX.Get()->SetGlobalSimulationSpeed (1.0f); // set the number of threads @@ -125,7 +124,6 @@ namespace EMotionFX m_recorder = nullptr; m_motionInstancePool = nullptr; m_debugDraw = nullptr; - m_renderActorSettings = nullptr; m_unitType = MCore::Distance::UNITTYPE_METERS; m_globalSimulationSpeed = 1.0f; m_isInEditorMode = false; @@ -138,6 +136,8 @@ namespace EMotionFX { RegisterMemoryCategories(MCore::GetMemoryTracker()); } + + m_renderActorSettings = AZStd::make_unique(); } @@ -170,8 +170,7 @@ namespace EMotionFX delete m_debugDraw; m_debugDraw = nullptr; - delete m_renderActorSettings; - m_renderActorSettings = nullptr; + m_renderActorSettings.reset(); m_eventManager->Destroy(); m_eventManager = nullptr; @@ -316,11 +315,6 @@ namespace EMotionFX m_debugDraw = draw; } - void EMotionFXManager::SetRenderActorSettings(AZ::Render::RenderActorSettings* settings) - { - m_renderActorSettings = settings; - } - // set the motion instance pool void EMotionFXManager::SetMotionInstancePool(MotionInstancePool* pool) { diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h index 41b57cb2d8..4d55143b2f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Source/EMotionFXManager.h @@ -192,9 +192,9 @@ namespace EMotionFX * Get the render actor settings * @result A pointer to global render actor settings. */ - MCORE_INLINE AZ::Render::RenderActorSettings* GetRenderActorSettings() const + AZ::Render::RenderActorSettings* GetRenderActorSettings() const { - return m_renderActorSettings; + return m_renderActorSettings.get(); } /** @@ -360,7 +360,7 @@ namespace EMotionFX Recorder* m_recorder; /**< The recorder. */ MotionInstancePool* m_motionInstancePool; /**< The motion instance pool. */ DebugDraw* m_debugDraw; /**< The debug drawing system. */ - AZ::Render::RenderActorSettings* m_renderActorSettings; /**< The global render actor settings. */ + AZStd::unique_ptr m_renderActorSettings; /**< The global render actor settings. */ AZStd::vector m_threadDatas; /**< The per thread data. */ MCore::Distance::EUnitType m_unitType; /**< The unit type, on default it is MCore::Distance::UNITTYPE_METERS. */ @@ -427,12 +427,6 @@ namespace EMotionFX */ void SetDebugDraw(DebugDraw* draw); - /** - * Set the render actor settings. - * @param settings The render actor settings. - */ - void SetRenderActorSettings(AZ::Render::RenderActorSettings* settings); - /** * Set the motion instance pool. * @param pool The motion instance pool. @@ -526,5 +520,5 @@ namespace EMotionFX MCORE_INLINE Recorder& GetRecorder() { return *GetEMotionFX().GetRecorder(); } /**< Get the recorder. */ MCORE_INLINE MotionInstancePool& GetMotionInstancePool() { return *GetEMotionFX().GetMotionInstancePool(); } /**< Get the motion instance pool. */ MCORE_INLINE DebugDraw& GetDebugDraw() { return *GetEMotionFX().GetDebugDraw(); } /**< Get the debug drawing. */ - MCORE_INLINE AZ::Render::RenderActorSettings& GetRenderActorSettings() { return *GetEMotionFX().GetRenderActorSettings(); }/**< Get the render actor settings. */ + MCORE_INLINE AZ::Render::RenderActorSettings& GetRenderActorSettings() { return *GetEMotionFX().GetRenderActorSettings(); }/**< Get the render actor settings. */ } // namespace EMotionFX diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp index 46c3703949..496781d316 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderOptions.cpp @@ -316,8 +316,7 @@ namespace EMStudio options.m_manipulatorMode = static_cast(settings->value("manipulatorMode", options.m_manipulatorMode).toInt()); - AZ::Render::RenderActorSettings& renderActorSettings = EMotionFX::GetRenderActorSettings(); - options.CopyToRenderActorSettings(renderActorSettings); + options.CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); return options; } @@ -1083,16 +1082,19 @@ namespace EMStudio void RenderOptions::OnVertexNormalsScaleChangedCallback() const { PluginOptionsNotificationsBus::Event(s_vertexNormalsScaleOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_vertexNormalsScaleOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnFaceNormalsScaleChangedCallback() const { PluginOptionsNotificationsBus::Event(s_faceNormalsScaleOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_faceNormalsScaleOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnTangentsScaleChangedCallback() const { PluginOptionsNotificationsBus::Event(s_tangentsScaleOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_tangentsScaleOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnNodeOrientationScaleChangedCallback() const @@ -1193,6 +1195,7 @@ namespace EMStudio void RenderOptions::OnWireframeColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_wireframeColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_wireframeColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnCollisionMeshColorChangedCallback() const @@ -1203,26 +1206,31 @@ namespace EMStudio void RenderOptions::OnVertexNormalsColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_vertexNormalsColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_vertexNormalsColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnFaceNormalsColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_faceNormalsColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_faceNormalsColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnTangentsColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_tangentsColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_tangentsColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnMirroredBitangentsColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_mirroredBitangentsColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_mirroredBitangentsColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnBitangentsColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_bitangentsColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_bitangentsColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnNodeAABBColorChangedCallback() const @@ -1233,6 +1241,7 @@ namespace EMStudio void RenderOptions::OnStaticAABBColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_staticAABBColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_staticAABBColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnMeshAABBColorChangedCallback() const @@ -1243,6 +1252,7 @@ namespace EMStudio void RenderOptions::OnLineSkeletonColorChangedCallback() const { PluginOptionsNotificationsBus::Event(s_lineSkeletonColorOptionName, &PluginOptionsNotificationsBus::Events::OnOptionChanged, s_lineSkeletonColorOptionName); + CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); } void RenderOptions::OnSkeletonColorChangedCallback() const diff --git a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h index a23860bcb8..58bed325d0 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h +++ b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h @@ -8,6 +8,7 @@ #pragma once #include +#include namespace AZ::Render { @@ -16,6 +17,9 @@ namespace AZ::Render class RenderActorSettings { public: + AZ_RTTI(RenderActorSettings, "{240BDFE2-D7F5-4927-A8CA-D2945E41AFFD}"); + AZ_CLASS_ALLOCATOR(RenderActorSettings, AZ::SystemAllocator, 0) + float m_vertexNormalsScale = 1.0f; float m_faceNormalsScale = 1.0f; float m_tangentsScale = 1.0f; From b3301414ad1f76161fa88eaf8650f42bfb94617c Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Wed, 3 Nov 2021 08:54:00 -0500 Subject: [PATCH 161/200] Remove AssetProcessorManagerTest AssertAbsorber and update test to use the one from the base class instead (#5216) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AssetProcessorManagerTest.cpp | 32 +++++++++---------- .../assetmanager/AssetProcessorManagerTest.h | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 656d7cab4e..5bcb6dc583 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -244,7 +244,7 @@ void AssetProcessorManagerTest::SetUp() AZ_Printf("UnitTest", "Allocating APM\n") m_assetProcessorManager.reset(new AssetProcessorManager_Test(m_config.get())); AZ_Printf("UnitTest", "APM ready\n"); - m_assertAbsorber.Clear(); + m_errorAbsorber->Clear(); m_isIdling = false; @@ -335,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) @@ -389,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); } @@ -1313,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(); } @@ -1618,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)); @@ -1628,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. @@ -1946,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) @@ -2094,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) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.h index d5afd8520f..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; From ab76c6218883c3b8db18a08b4fac813497cea1d0 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Wed, 3 Nov 2021 09:07:00 -0600 Subject: [PATCH 162/200] Allow input devices to be constructed with a custom implementation. (#5217) * Allow input devices to be constructed with a custom implementation. This augments the existing functionality that allows for an input device implementation to be swapped out at runtime, Signed-off-by: bosnichd * Updates based on review feedback, and fix for clang builds. Signed-off-by: bosnichd * Update based on review feedback, and change the InputDeviceImplementationRequest bus to use the same ImplementationFactory type alias. Signed-off-by: bosnichd --- .../Buses/Requests/InputDeviceRequestBus.h | 18 +++++------------- .../Devices/Gamepad/InputDeviceGamepad.cpp | 13 ++++++++++--- .../Input/Devices/Gamepad/InputDeviceGamepad.h | 15 +++++++++++++++ .../Devices/Keyboard/InputDeviceKeyboard.cpp | 9 +++++---- .../Devices/Keyboard/InputDeviceKeyboard.h | 13 ++++++++++++- .../Input/Devices/Motion/InputDeviceMotion.cpp | 9 +++++---- .../Input/Devices/Motion/InputDeviceMotion.h | 13 ++++++++++++- .../Input/Devices/Mouse/InputDeviceMouse.cpp | 9 +++++---- .../Input/Devices/Mouse/InputDeviceMouse.h | 13 ++++++++++++- .../Input/Devices/Touch/InputDeviceTouch.cpp | 9 +++++---- .../Input/Devices/Touch/InputDeviceTouch.h | 13 ++++++++++++- .../InputDeviceVirtualKeyboard.cpp | 9 +++++---- .../InputDeviceVirtualKeyboard.h | 13 ++++++++++++- 13 files changed, 115 insertions(+), 41 deletions(-) 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 From 246debd50a8b9d80ff3c9fd6afdf5cf98caed845 Mon Sep 17 00:00:00 2001 From: rhhong Date: Wed, 3 Nov 2021 09:27:42 -0700 Subject: [PATCH 163/200] fix android compile error Signed-off-by: rhhong --- .../Code/Source/Integration/Rendering/RenderActorSettings.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h index 58bed325d0..3e4f5ff5c9 100644 --- a/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h +++ b/Gems/EMotionFX/Code/Source/Integration/Rendering/RenderActorSettings.h @@ -20,6 +20,8 @@ namespace AZ::Render AZ_RTTI(RenderActorSettings, "{240BDFE2-D7F5-4927-A8CA-D2945E41AFFD}"); AZ_CLASS_ALLOCATOR(RenderActorSettings, AZ::SystemAllocator, 0) + virtual ~RenderActorSettings() = default; + float m_vertexNormalsScale = 1.0f; float m_faceNormalsScale = 1.0f; float m_tangentsScale = 1.0f; From d584732116c0493a56fa2617089b441f8facfbba Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Wed, 3 Nov 2021 10:45:12 -0700 Subject: [PATCH 164/200] Fix ap log path on s3 (#5257) * Fix typo when calling upload_to_s3.py Signed-off-by: shiranj * Remove space in extra_args Signed-off-by: shiranj --- scripts/build/Jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 127d6b80ca..ff04902861 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -450,7 +450,7 @@ def UploadAPLogs(Map options, String branchName, String jobName, String workspac def command = "${pythonPath} -u ${s3UploadScriptPath} --base_dir ${apLogsPath} " + "--file_regex \".*\" --bucket ${env.AP_LOGS_S3_BUCKET} " + "--search_subdirectories True --key_prefix ${env.JENKINS_JOB_NAME}/${branchName}/${env.BUILD_NUMBER}/${jobName} " + - "--extra_args {\"ACL\": \"bucket-owner-full-control\"}" + '--extra_args {\\"ACL\\":\\"bucket-owner-full-control\\"}' palSh(command, "Uploading AP logs for job ${jobName} for branch ${branchName}", false) } } From 9a15b7cadc4c4432a31c5e1ea09e51d0bcce196d Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Wed, 3 Nov 2021 11:18:57 -0700 Subject: [PATCH 165/200] 1. Fix "Open Editor" button not launching Editor on Mac. 2. Update LaunchAssetProcessor() paths on Mac. 3. LaunchAssetProcessor() uses ProcessWatcher wrappers. 4. SDK Launcher registers the engine when launching. Signed-off-by: amzn-sj --- .../Asset/AssetSystemComponentHelper_Mac.cpp | 32 ++++++++++-------- .../BundleLauncher/O3DE_SDK_Launcher.cpp | 6 ++++ .../Platform/Linux/ProjectUtils_linux.cpp | 5 +++ .../Platform/Mac/ProjectUtils_mac.cpp | 33 +++++++++++++++++++ .../Platform/Windows/ProjectUtils_windows.cpp | 5 +++ .../ProjectManager/Source/ProjectUtils.h | 4 ++- .../ProjectManager/Source/ProjectsScreen.cpp | 4 +-- 7 files changed, 73 insertions(+), 16 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp index c6f481b65b..a3381dabb8 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/Asset/AssetSystemComponentHelper_Mac.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include @@ -24,14 +26,20 @@ namespace AzFramework::AssetSystem::Platform AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory }; // In Mac the Editor and game is within a bundle, so the path to the sibling app // has to go up from the Contents/MacOS folder the binary is in - assetProcessorPath /= "../../../AssetProcessor.app"; + assetProcessorPath /= "../../../AssetProcessor.app/Contents/MacOS/AssetProcessor"; assetProcessorPath = assetProcessorPath.LexicallyNormal(); if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { - // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. - assetProcessorPath = - AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app"; + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (AZ::IO::FixedMaxPath installedBinariesPath; + settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder)) + { + // Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure. + assetProcessorPath = AZ::IO::FixedMaxPath{ engineRoot } / installedBinariesPath / "AssetProcessor.app/Contents/MacOS/AssetProcessor"; + } + } if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str())) { @@ -39,23 +47,21 @@ namespace AzFramework::AssetSystem::Platform } } - auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"(open -g "%s" --args --start-hidden)", assetProcessorPath.c_str()); + AZStd::string commandLineParams; // Add the engine path to the launch command if not empty if (!engineRoot.empty()) { - fullLaunchCommand += R"( --engine-path=")"; - fullLaunchCommand += engineRoot; - fullLaunchCommand += '"'; + commandLineParams += AZStd::string::format("\"--engine-path=\"%s\"\"", engineRoot.data()); } - // Add the active project path to the launch command if not empty if (!projectPath.empty()) { - fullLaunchCommand += R"( --project-path=")"; - fullLaunchCommand += projectPath; - fullLaunchCommand += '"'; + commandLineParams += AZStd::string::format(" \"--regset=/Amazon/AzCore/Bootstrap/project_path=\"%s\"\"", projectPath.data()); } - return system(fullLaunchCommand.c_str()) == 0; + AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; + processLaunchInfo.m_processExecutableString = AZStd::move(assetProcessorPath.Native()); + processLaunchInfo.m_commandlineParameters = commandLineParams; + return AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo); } } diff --git a/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp b/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp index 0c362ac829..4dd7e184e9 100644 --- a/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp +++ b/Code/Tools/BundleLauncher/O3DE_SDK_Launcher.cpp @@ -49,6 +49,12 @@ int main(int argc, char* argv[]) AZStd::unique_ptr shellProcess(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE)); shellProcess->WaitForProcessToExit(120); shellProcess.reset(); + + parameters = AZStd::string::format("-c \"%s/scripts/o3de.sh register --this-engine\"", enginePath.c_str()); + shellProcessLaunch.m_commandlineParameters = parameters; + shellProcess.reset(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE)); + shellProcess->WaitForProcessToExit(120); + shellProcess.reset(); AZ::IO::FixedMaxPath projectManagerPath = installedBinariesFolder/"o3de.app"/"Contents"/"MacOS"/"o3de"; AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index 0d66009d90..abb062c08a 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -94,5 +94,10 @@ namespace O3DE::ProjectManager QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } + + AZ::IO::FixedMaxPath GetEditorDirectory() + { + return AZ::Utils::GetExecutableDirectory(); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index e36f6cd0c8..b768200398 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include + namespace O3DE::ProjectManager { namespace ProjectUtils @@ -104,5 +107,35 @@ namespace O3DE::ProjectManager QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } + + AZ::IO::FixedMaxPath GetEditorDirectory() + { + AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory(); + AZ::IO::FixedMaxPath editorPath{ executableDirectory }; + editorPath /= "../../../Editor.app/Contents/MacOS"; + editorPath = editorPath.LexicallyNormal(); + if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str())) + { + if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr) + { + if (AZ::IO::FixedMaxPath installedBinariesPath; + settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder)) + { + if (AZ::IO::FixedMaxPath engineRootFolder; + settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder)) + { + editorPath = engineRootFolder / installedBinariesPath / "Editor.app/Contents/MacOS"; + } + } + } + + if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str())) + { + AZ_Error("ProjectManager", false, "Unable to find the Editor app bundle!"); + } + } + + return editorPath; + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 831529d5e4..10344bf42f 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -139,5 +139,10 @@ namespace O3DE::ProjectManager QProcessEnvironment::systemEnvironment(), QObject::tr("Running get_python script...")); } + + AZ::IO::FixedMaxPath GetEditorDirectory() + { + return AZ::Utils::GetExecutableDirectory(); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 1fdf76913e..890d50d2de 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace O3DE::ProjectManager @@ -67,7 +68,8 @@ namespace O3DE::ProjectManager AZ::Outcome GetProjectBuildPath(const QString& projectPath); AZ::Outcome OpenCMakeGUI(const QString& projectPath); AZ::Outcome RunGetPythonScript(const QString& enginePath); - + + AZ::IO::FixedMaxPath GetEditorDirectory(); } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index cf42da88fa..f86a689e59 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -392,11 +392,11 @@ namespace O3DE::ProjectManager { if (!WarnIfInBuildQueue(projectPath)) { - AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory(); + AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory(); AZStd::string executableFilename = "Editor"; AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION); auto cmdPath = AZ::IO::FixedMaxPathString::format( - "%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), + "%s --regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(), projectPath.toStdString().c_str()); AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo; From 815c2d198645b094b3eff0293751446f3ed62cd4 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Wed, 3 Nov 2021 13:19:22 -0500 Subject: [PATCH 166/200] {lyn5868} fixing the asset_processor_batch_tests.py auto tests (#5247) Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> --- .../asset_processor_batch_tests.py | 21 +++++++------------ .../assets/C1568831/cgf_to_delete.cgf | 3 --- .../assets/C1568831/fbx_to_delete.fbx | 3 --- .../assets/C1568831/file_to_delete.prefab | 1 + .../assets/C1568831/file_to_delete.txt | 1 + .../assets/C1571774/test_mesh_robot.cgf | 3 --- .../assets/C1591338/test_mesh_robot.cgf | 3 --- .../assets/C1591338/test_mesh_robot.prefab | 1 + .../Energy_Background_One.png | 3 --- .../Energy_Background_Two.png | 3 --- .../Init.bnk | 3 --- .../entity_icon_example_2.png | 3 --- .../SoundWave_1.png | 3 --- .../extra_file.prefab | 1 + .../test_cube.fbx | 3 --- .../ly_test_tools/o3de/asset_processor.py | 12 ++++++----- 16 files changed, 18 insertions(+), 49 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png create mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab delete mode 100644 AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py index f3483d9c1f..2d67bca8fe 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_processor_batch_tests.py @@ -329,7 +329,7 @@ class TestsAssetProcessorBatch_AllPlatforms(object): # or an expected behavior has changed. Processing bootstrap.cfg sometimes but not other times should not # cause a failure in this test. num_processed_assets = asset_processor_utils.get_num_processed_assets(output) - assert num_processed_assets >= 8, f'Wrong number of successfully processed assets found in output: '\ + assert num_processed_assets >= 6, f'Wrong number of successfully processed assets found in output: '\ '{num_processed_assets}' missing_assets, _ = asset_processor.compare_assets_with_cache() @@ -585,20 +585,18 @@ class TestsAssetProcessorBatch_AllPlatforms(object): 3. Verify that logs exist for both AP Batch & AP GUI """ asset_processor.create_temp_asset_root() + asset_processor.create_temp_log_root() LOG_PATH = { "batch_log": workspace.paths.ap_batch_log(), - "gui_log": workspace.paths.ap_gui_log(), - "job_logs": workspace.paths.ap_job_logs(), + "gui_log": workspace.paths.ap_gui_log() } class LogTimes: batch_log_start_time = 0 gui_log_start_time = 0 - job_logs_start_time = 0 batch_log_final_time = 0 gui_log_final_time = 0 - job_logs_final_time = 0 @staticmethod def Report(): @@ -607,12 +605,10 @@ class TestsAssetProcessorBatch_AllPlatforms(object): Original Times: Batch: {LogTimes.batch_log_start_time} GUI: {LogTimes.gui_log_start_time} - JobLogs:{LogTimes.job_logs_start_time} Post-Run Times: Batch: {LogTimes.batch_log_final_time} GUI: {LogTimes.gui_log_final_time} - JobLogs:{LogTimes.job_logs_final_time} """ ) @@ -629,23 +625,19 @@ class TestsAssetProcessorBatch_AllPlatforms(object): LogTimes.Report() def check_existence(name, path): - assert os.path.exists(path), f"{name} could not be located after running the AP." + assert os.path.exists(path), f"{name} could not be located {path} after running the AP." # Check if log files previously exist and grab their modification times update_times("_start_time") # Run the Batch process - assert asset_processor.batch_process(), "Batch process failed to successfully terminate" + assert asset_processor.batch_process(create_temp_log=False), "Batch process failed to successfully terminate" - asset_processor.gui_process(quitonidle=True) + asset_processor.gui_process(quitonidle=True, create_temp_log=False) # Check that the Logs directory exists (C1564055) check_existence("Logs Directory", workspace.paths.ap_log_dir()) - # Check that the logs and JobLogs directory have updated modified times (C1564056) - for key in LOG_PATH.keys(): - check_existence(key, LOG_PATH[key]) - update_times("_final_time") for key in LOG_PATH.keys(): @@ -708,6 +700,7 @@ class TestsAssetProcessorBatch_AllPlatforms(object): @pytest.mark.BAT @pytest.mark.assetpipeline + @pytest.mark.skip(reason="need to change assets from .slice files to an asset type that can have nested dependencies") def test_validateNestedPreloadDependency_Found(self, asset_processor, ap_setup_fixture, workspace): """ Tests processing of a nested circular dependency and verifies that Asset Processor will return an error diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf deleted file mode 100644 index 47571e39a9..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/cgf_to_delete.cgf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7932fada1523fad4eb6ad5c13111bb4c00d6b0584ec8641060bf25f306b17e69 -size 84632 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx deleted file mode 100644 index 165bc01a54..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/fbx_to_delete.fbx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bf94b548eccb78432db65077124cadf20de975919b181d712fde081f59edd353 -size 38848 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.prefab @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt new file mode 100644 index 0000000000..3d789f8b83 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1568831/file_to_delete.txt @@ -0,0 +1 @@ +to be deleted \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf deleted file mode 100644 index fcb3513ed0..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1571774/test_mesh_robot.cgf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1675471085483e0bd252a5bdd4db1b365c66f16ac32a6e6dd70bb1c23df83fa5 -size 24160 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf deleted file mode 100644 index fcb3513ed0..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.cgf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1675471085483e0bd252a5bdd4db1b365c66f16ac32a6e6dd70bb1c23df83fa5 -size 24160 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/C1591338/test_mesh_robot.prefab @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png deleted file mode 100644 index e012e887e7..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_One.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:21df6ab62f2572daa6d0710ad6819a728ee751a62170903a6773563d614aa51f -size 15191 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png deleted file mode 100644 index e012e887e7..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_AddSameAssetsDifferentNames_ShouldProcess/Energy_Background_Two.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:21df6ab62f2572daa6d0710ad6819a728ee751a62170903a6773563d614aa51f -size 15191 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk deleted file mode 100644 index f525a402af..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/Init.bnk +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f0b4750147acbcc6229a1043ed47ee48e7703a5241f27fc72976e95741144369 -size 2372 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png deleted file mode 100644 index 47e2d35331..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessAndDeleteCache_APBatchShouldReprocess/entity_icon_example_2.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a036c3763b96079dde8505ad6995f8b717a777c78d7a434ac8de6f1ccb5d8dd1 -size 4327 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png deleted file mode 100644 index b3b8fba4a1..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/SoundWave_1.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf55a4372d82d70d8cdcc95468367cd4fad7649d3fb99c4d85049977b506885c -size 13429 diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/extra_file.prefab @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx deleted file mode 100644 index 57fa7b327c..0000000000 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/assets/test_ProcessByBothApAndBatch_Md5ShouldMatch/test_cube.fbx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1821d000b583821fd36ec73f91073d51ae90762225a34a81a74771c36236b5e1 -size 12963 diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py index 2019f21004..9f8ee9649e 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py @@ -427,8 +427,9 @@ class AssetProcessor(object): def batch_process(self, timeout=DEFAULT_TIMEOUT_SECONDS, fastscan=True, capture_output=False, platforms=None, extra_params=None, add_gem_scan_folders=None, add_config_scan_folders=None, decode=True, - expect_failure=False, scan_folder_pattern=None): - self.create_temp_log_root() + expect_failure=False, scan_folder_pattern=None, create_temp_log=True): + if create_temp_log: + self.create_temp_log_root() ap_path = self._workspace.paths.asset_processor_batch() command = self.build_ap_command(ap_path=ap_path, fastscan=fastscan, platforms=platforms, extra_params=extra_params, add_gem_scan_folders=add_gem_scan_folders, @@ -442,7 +443,7 @@ class AssetProcessor(object): def gui_process(self, timeout=DEFAULT_TIMEOUT_SECONDS, fastscan=True, capture_output=False, platforms=None, extra_params=None, add_gem_scan_folders=None, add_config_scan_folders=None, decode=True, expect_failure=False, quitonidle=False, connect_to_ap=False, accept_input=True, run_until_idle=True, - scan_folder_pattern=None): + scan_folder_pattern=None, create_temp_log=True): ap_path = os.path.abspath(self._workspace.paths.asset_processor()) ap_exe_path = os.path.dirname(ap_path) extra_gui_params = [] @@ -472,7 +473,8 @@ class AssetProcessor(object): else: extra_gui_params.append(extra_params) - self.create_temp_log_root() + if create_temp_log: + self.create_temp_log_root() command = self.build_ap_command(ap_path=ap_path, fastscan=fastscan, platforms=platforms, extra_params=extra_gui_params, add_gem_scan_folders=add_gem_scan_folders, add_config_scan_folders=add_config_scan_folders, @@ -580,7 +582,7 @@ class AssetProcessor(object): if isinstance(platforms, list): platforms = ','.join(platforms) command.append(f'--platforms={platforms}') - for key, value in self._enabled_platform_overrides: + for key, value in self._enabled_platform_overrides.items(): command.append(f'--regset="f{ASSET_PROCESSOR_SETTINGS_ROOT_KEY}/Platforms/{key}={value}"') if extra_params: From 0e8edfa70217777ba9ace1dc12df1d8f5277f800 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Wed, 3 Nov 2021 11:37:28 -0700 Subject: [PATCH 167/200] Update OpenMesh for Windows and prepare for Linux and Mac (#5248) - Update to OpenMesh-8.1-rev3 for Windows - Add OpenMesh-8.1-rev3 for Linux but not enabled - Add OpenMesh-8.1-rev3 for Mac but not enabled Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- .../Platform/Linux/platform_linux_tools.cmake | 16 ++++++++++++++++ .../Source/Platform/Mac/platform_mac_tools.cmake | 16 ++++++++++++++++ .../Windows/platform_windows_tools.cmake | 2 +- .../Platform/Linux/BuiltInPackages_linux.cmake | 1 + .../Platform/Mac/BuiltInPackages_mac.cmake | 1 + .../Windows/BuiltInPackages_windows.cmake | 2 +- 6 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 Gems/WhiteBox/Code/Source/Platform/Linux/platform_linux_tools.cmake create mode 100644 Gems/WhiteBox/Code/Source/Platform/Mac/platform_mac_tools.cmake diff --git a/Gems/WhiteBox/Code/Source/Platform/Linux/platform_linux_tools.cmake b/Gems/WhiteBox/Code/Source/Platform/Linux/platform_linux_tools.cmake new file mode 100644 index 0000000000..ca99817d82 --- /dev/null +++ b/Gems/WhiteBox/Code/Source/Platform/Linux/platform_linux_tools.cmake @@ -0,0 +1,16 @@ +# +# 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_HOST_TOOLS) + + ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux TARGETS OpenMesh PACKAGE_HASH 805bd0b24911bb00c7f575b8c3f10d7ea16548a5014c40811894a9445f17a126) + + set(LY_BUILD_DEPENDENCIES + PRIVATE + 3rdParty::OpenMesh) +endif() diff --git a/Gems/WhiteBox/Code/Source/Platform/Mac/platform_mac_tools.cmake b/Gems/WhiteBox/Code/Source/Platform/Mac/platform_mac_tools.cmake new file mode 100644 index 0000000000..030b621642 --- /dev/null +++ b/Gems/WhiteBox/Code/Source/Platform/Mac/platform_mac_tools.cmake @@ -0,0 +1,16 @@ +# +# 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_HOST_TOOLS) + + ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-mac TARGETS OpenMesh PACKAGE_HASH af92db02a25c1f7e1741ec898f49d81d52631e00336bf9bddd1e191590063c2f) + + set(LY_BUILD_DEPENDENCIES + PRIVATE + 3rdParty::OpenMesh) +endif() diff --git a/Gems/WhiteBox/Code/Source/Platform/Windows/platform_windows_tools.cmake b/Gems/WhiteBox/Code/Source/Platform/Windows/platform_windows_tools.cmake index 437dbc192d..aa56fe7b23 100644 --- a/Gems/WhiteBox/Code/Source/Platform/Windows/platform_windows_tools.cmake +++ b/Gems/WhiteBox/Code/Source/Platform/Windows/platform_windows_tools.cmake @@ -8,7 +8,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) - ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows TARGETS OpenMesh PACKAGE_HASH 1c1df639358526c368e790dfce40c45cbdfcfb1c9a041b9d7054a8949d88ee77) + ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-windows TARGETS OpenMesh PACKAGE_HASH 7a6309323ad03bfc646bd04ecc79c3711de6790e4ff5a72f83a8f5a8f496d684) set(LY_BUILD_DEPENDENCIES PRIVATE diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index af7afff5dc..25424a348c 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -36,6 +36,7 @@ ly_associate_package(PACKAGE_NAME unwind-1.2.1-linux ly_associate_package(PACKAGE_NAME qt-5.15.2-rev6-linux TARGETS Qt PACKAGE_HASH a37bd9989f1e8fe57d94b98cbf9bd5c3caaea740e2f314e5162fa77300551531) ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-linux TARGETS libpng PACKAGE_HASH 896451999f1de76375599aec4b34ae0573d8d34620d9ab29cc30b8739c265ba6) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-linux TARGETS libsamplerate PACKAGE_HASH 41643c31bc6b7d037f895f89d8d8d6369e906b92eff42b0fe05ee6a100f06261) +ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-linux TARGETS OpenMesh PACKAGE_HASH 805bd0b24911bb00c7f575b8c3f10d7ea16548a5014c40811894a9445f17a126) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-linux TARGETS OpenSSL PACKAGE_HASH b779426d1e9c5ddf71160d5ae2e639c3b956e0fb5e9fcaf9ce97c4526024e3bc) ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-linux TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 88c4a359325d749bc34090b9ac466424847f3b71ba0de15045cf355c17c07099) ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-linux TARGETS SPIRVCross PACKAGE_HASH 7889ee5460a688e9b910c0168b31445c0079d363affa07b25d4c8aeb608a0b80) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index d054ba22e1..1ac7568a98 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -33,6 +33,7 @@ ly_associate_package(PACKAGE_NAME mcpp-2.7.2_az.2-rev1-mac ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-mac TARGETS mikkelsen PACKAGE_HASH 83af99ca8bee123684ad254263add556f0cf49486c0b3e32e6d303535714e505) ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac TARGETS googletest PACKAGE_HASH cbf020d5ef976c5db8b6e894c6c63151ade85ed98e7c502729dd20172acae5a8) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-mac TARGETS GoogleBenchmark PACKAGE_HASH ad25de0146769c91e179953d845de2bec8ed4a691f973f47e3eb37639381f665) +ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-mac TARGETS OpenMesh PACKAGE_HASH af92db02a25c1f7e1741ec898f49d81d52631e00336bf9bddd1e191590063c2f) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac TARGETS OpenSSL PACKAGE_HASH 28adc1c0616ac0482b2a9d7b4a3a3635a1020e87b163f8aba687c501cf35f96c) ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e) ly_associate_package(PACKAGE_NAME libpng-1.6.37-mac TARGETS libpng PACKAGE_HASH 1ad76cd038ccc1f288f83c5fe2859a0f35c5154e1fe7658e1230cc428d318a8b) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index fce2229771..3189625611 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -40,7 +40,7 @@ ly_associate_package(PACKAGE_NAME openimageio-2.1.16.0-rev2-windows ly_associate_package(PACKAGE_NAME qt-5.15.2-rev4-windows TARGETS Qt PACKAGE_HASH a4634caaf48192cad5c5f408504746e53d338856148285057274f6a0ccdc071d) ly_associate_package(PACKAGE_NAME libpng-1.6.37-rev1-windows TARGETS libpng PACKAGE_HASH aa20c894fbd7cdaea585a54e37620b3454a7e414a58128acd68ccf6fe76c47d6) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-windows TARGETS libsamplerate PACKAGE_HASH dcf3c11a96f212a52e2c9241abde5c364ee90b0f32fe6eeb6dcdca01d491829f) -ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev1-windows TARGETS OpenMesh PACKAGE_HASH 1c1df639358526c368e790dfce40c45cbdfcfb1c9a041b9d7054a8949d88ee77) +ly_associate_package(PACKAGE_NAME OpenMesh-8.1-rev3-windows TARGETS OpenMesh PACKAGE_HASH 7a6309323ad03bfc646bd04ecc79c3711de6790e4ff5a72f83a8f5a8f496d684) ly_associate_package(PACKAGE_NAME civetweb-1.8-rev1-windows TARGETS civetweb PACKAGE_HASH 36d0e58a59bcdb4dd70493fb1b177aa0354c945b06c30416348fd326cf323dd4) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev2-windows TARGETS OpenSSL PACKAGE_HASH 9af1c50343f89146b4053101a7aeb20513319a3fe2f007e356d7ce25f9241040) ly_associate_package(PACKAGE_NAME Crashpad-0.8.0-rev1-windows TARGETS Crashpad PACKAGE_HASH d162aa3070147bc0130a44caab02c5fe58606910252caf7f90472bd48d4e31e2) From 41d3a38781674dbedd8ea936c00a731518cdb2c6 Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Wed, 3 Nov 2021 12:42:22 -0700 Subject: [PATCH 168/200] Add missing header file Signed-off-by: amzn-sj --- Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp | 2 ++ .../ProjectManager/Platform/Windows/ProjectUtils_windows.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index abb062c08a..e901d807b4 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -10,6 +10,8 @@ #include #include +#include + namespace O3DE::ProjectManager { namespace ProjectUtils diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 10344bf42f..871f8e9567 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -14,6 +14,8 @@ #include #include +#include + namespace O3DE::ProjectManager { namespace ProjectUtils From 427741426873421abd0e13234bcf89cb35ec8666 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 3 Nov 2021 13:31:56 -0700 Subject: [PATCH 169/200] bugfix: cycle mouse to the other side of the screen when using scrollbox (#5048) * bugfix: cycle mouse to the other side of the screen when using scrollbox Signed-off-by: Michael Pollind * chore: added comments to SpinBox Signed-off-by: Michael Pollind --- .../AzQtComponents/Components/Widgets/SpinBox.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp index 06361ceee9..8ace8d0f40 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SpinBox.cpp @@ -657,13 +657,18 @@ bool SpinBoxWatcher::handleMouseDragStepping(QAbstractSpinBox* spinBox, QEvent* QPoint screenPos = mouseEvent->screenPos().toPoint(); const int xPos = screenPos.x(); int newXPos = xPos; + // cursor bounces on the left and right side of the screen + // looks like buggy behaviour so mouse cursor is wrapped + // around to the other side of the screen. if (xPos >= screenRect.right()) { - newXPos = screenRect.right() - 1; + // wraps mouse cursor around to the left side of the screen + newXPos = screenRect.left() + 1; } else if (xPos <= screenRect.left()) { - newXPos = screenRect.left() + 1; + // wraps mouse cursor around to the right side of the screen + newXPos = screenRect.right() - 1; } if (newXPos != xPos) From 062c38e7e9ac26fafe778fa7f08306c6ac6066ee Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Wed, 3 Nov 2021 13:46:17 -0700 Subject: [PATCH 170/200] Update README.md CMake link and instructions Signed-off-by: Mike Chang --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1191a0f0ee..6f500a3dd3 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ For the latest details and system requirements, refer to [System Requirements](h * Game Development with C++ * MSVC v142 - VS 2019 C++ x64/x86 * C++ 2019 redistributable update -* CMake 3.20.5 minimum: [https://cmake.org/download/](https://cmake.org/download/) +* CMake 3.20.5 minimum: [https://cmake.org/download/#latest](https://cmake.org/download/#latest) (Release Candidate versions are not supported) #### Optional From 620e522f86d643903f231a753d8f5b92ffb48453 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 20 Oct 2021 10:25:05 -0500 Subject: [PATCH 171/200] material editor and exporter save source materials with relative paths Signed-off-by: Guthrie Adams --- .../Material/MaterialTypeSourceData.h | 4 - .../Material/MaterialTypeSourceData.cpp | 42 ------- .../Util/MaterialPropertyUtil.h | 12 +- .../Code/Source/Util/MaterialPropertyUtil.cpp | 48 +++++++- .../Code/Source/Document/MaterialDocument.cpp | 110 ++++++++++-------- .../Code/Source/Document/MaterialDocument.h | 5 +- .../Material/EditorMaterialComponentUtil.cpp | 52 +++++---- 7 files changed, 151 insertions(+), 122 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 1234b15f95..f5336807c7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -209,10 +209,6 @@ namespace AZ //! Traversal will stop once all properties have been enumerated or the callback function returns false void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const; - //! Convert the property value into the format that will be stored in the source data - //! This is primarily needed to support conversions of special types like enums and images - bool ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const; - Outcome> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; //! Possibly renames @propertyId based on the material version update steps. diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 08f57c7cd3..b208a49111 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -300,48 +300,6 @@ namespace AZ } } - bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const - { - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) - { - const uint32_t index = propertyValue.GetValue(); - if (index >= propertyDefinition.m_enumValues.size()) - { - AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); - return false; - } - - propertyValue = propertyDefinition.m_enumValues[index]; - return true; - } - - // Image asset references must be converted from asset IDs to a relative source file path - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is>()) - { - const Data::Asset& imageAsset = propertyValue.GetValue>(); - - Data::AssetInfo imageAssetInfo; - if (imageAsset.GetId().IsValid()) - { - bool result = false; - AZStd::string rootFilePath; - const AZStd::string platformName = ""; // Empty for default - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById, - imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath); - if (!result) - { - AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str()); - return false; - } - } - - propertyValue = imageAssetInfo.m_relativePath; - return true; - } - - return true; - } - Outcome> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const { MaterialTypeAssetCreator materialTypeAssetCreator; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index 333796493d..d888c76553 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -7,11 +7,12 @@ */ #pragma once -#include -#include #include #include #include +#include +#include +#include namespace AzToolsFramework { @@ -41,6 +42,13 @@ namespace AtomToolsFramework //! Compare equality of data types and values of editor property stored in AZStd::any bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB); + //! Convert the property value into the format that will be stored in the source data + //! This is primarily needed to support conversions of special types like enums and images + bool ConvertToExportFormat( + const AZ::IO::BasicPath& exportFolder, + const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, + AZ::RPI::MaterialPropertyValue& propertyValue); + //! Traverse up the instance data node hierarchy to find the containing dynamic property object const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode); } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 3f8a173918..b142977049 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -6,9 +6,10 @@ * */ -#include #include +#include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include namespace AtomToolsFramework @@ -163,6 +165,47 @@ namespace AtomToolsFramework return false; } + bool ConvertToExportFormat( + const AZ::IO::BasicPath& exportFolder, + const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, + AZ::RPI::MaterialPropertyValue& propertyValue) + { + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) + { + const uint32_t index = propertyValue.GetValue(); + if (index >= propertyDefinition.m_enumValues.size()) + { + AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); + return false; + } + + propertyValue = propertyDefinition.m_enumValues[index]; + return true; + } + + // Image asset references must be converted from asset IDs to a relative source file path + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image) + { + if (propertyValue.Is>()) + { + const auto& imageAsset = propertyValue.GetValue>(); + const auto& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); + propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + return true; + } + + if (propertyValue.Is>()) + { + const auto& image = propertyValue.GetValue>(); + const auto& sourcePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; + propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + return true; + } + } + + return true; + } + const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode) { // Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property @@ -172,7 +215,8 @@ namespace AtomToolsFramework const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata(); if (context && classData) { - if (context->CanDowncast(classData->m_typeId, azrtti_typeid(), classData->m_azRtti, nullptr)) + if (context->CanDowncast( + classData->m_typeId, azrtti_typeid(), classData->m_azRtti, nullptr)) { return static_cast(currentNode->FirstInstance()); } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 98af749261..ac07560d71 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -228,22 +228,22 @@ namespace MaterialEditor return false; } + AZ::IO::BasicPath exportFolder(m_absolutePath); + exportFolder.RemoveFilename(); + // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); - sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); - - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData( + exportFolder, sourceData, + [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -302,22 +302,22 @@ namespace MaterialEditor return false; } + AZ::IO::BasicPath exportFolder(normalizedSavePath); + exportFolder.RemoveFilename(); + // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); - sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); - - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData( + exportFolder, sourceData, + [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -375,17 +375,18 @@ namespace MaterialEditor return false; } + AZ::IO::BasicPath exportFolder(normalizedSavePath); + exportFolder.RemoveFilename(); + // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); - sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = m_relativePath; + sourceData.m_parentMaterial = AZ::IO::PathView(m_absolutePath).LexicallyRelative(exportFolder).StringAsPosix(); } // Force save data to store forward slashes @@ -393,9 +394,12 @@ namespace MaterialEditor AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); // populate sourceData with modified properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); - }); + const bool savedProperties = SavePropertiesToSourceData( + exportFolder, sourceData, + [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); + }); if (!savedProperties) { @@ -590,7 +594,10 @@ namespace MaterialEditor } } - bool MaterialDocument::SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const + bool MaterialDocument::SavePropertiesToSourceData( + const AZ::IO::BasicPath& exportFolder, + AZ::RPI::MaterialSourceData& sourceData, + PropertyFilterFunction propertyFilter) const { using namespace AZ; using namespace RPI; @@ -598,7 +605,7 @@ namespace MaterialEditor bool result = true; // populate sourceData with properties that meet the filter - m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { const MaterialPropertyId propertyId(groupName, propertyName); @@ -608,7 +615,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); result = false; @@ -663,8 +670,6 @@ namespace MaterialEditor return false; } - AZStd::string materialTypeSourceFilePath; - // The material document and inspector are constructed from source data if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialSourceData::Extension)) { @@ -677,27 +682,29 @@ namespace MaterialEditor // We must also always load the material type data for a complete, ordered set of the // groups and properties that will be needed for comparison and building the inspector - materialTypeSourceFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); - auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); - if (!materialTypeOutcome.IsSuccess()) + if (!m_materialSourceData.m_parentMaterial.empty()) { - AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", materialTypeSourceFilePath.c_str()); - return false; + m_materialSourceData.m_parentMaterial = + AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); } - m_materialTypeSourceData = materialTypeOutcome.GetValue(); - - if (MaterialSourceData::ApplyVersionUpdatesResult::Failed == m_materialSourceData.ApplyVersionUpdates(m_absolutePath)) + + if (!m_materialSourceData.m_materialType.empty()) + { + m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); + } + + auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); + if (!materialTypeOutcome.IsSuccess()) { - AZ_Error("MaterialDocument", false, "Material source data could not be auto updated to the latest version of the material type: '%s'.", m_materialSourceData.m_materialType.c_str()); + AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str()); return false; } + m_materialTypeSourceData = materialTypeOutcome.GetValue(); } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { - materialTypeSourceFilePath = m_absolutePath; - // Load the material type source data, which will be used for enumerating properties and building material source data - auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); + auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); if (!materialTypeOutcome.IsSuccess()) { AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); @@ -707,7 +714,7 @@ namespace MaterialEditor // The document represents a material, not a material type. // If the input data is a material type file we have to generate the material source data by referencing it. - m_materialSourceData.m_materialType = m_relativePath; + m_materialSourceData.m_materialType = m_absolutePath; m_materialSourceData.m_parentMaterial.clear(); } else @@ -870,7 +877,8 @@ namespace MaterialEditor m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); } - const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext(materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout()); + const MaterialFunctorSourceData::EditorContext editorContext = + MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); for (Ptr functorData : m_materialTypeSourceData.m_materialFunctorSourceData) { MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index 03997a2a91..7783ea2ba7 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -110,7 +110,10 @@ namespace MaterialEditor void OnAssetReloaded(AZ::Data::Asset asset) override; ////////////////////////////////////////////////////////////////////////// - bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; + bool SavePropertiesToSourceData( + const AZ::IO::BasicPath& exportFolder, + AZ::RPI::MaterialSourceData& sourceData, + PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index d15db886d6..c775676e68 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -97,29 +98,38 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { + AZ::IO::BasicPath exportFolder(path); + exportFolder.RemoveFilename(); + // Construct the material source data object that will be exported AZ::RPI::MaterialSourceData exportData; // Converting absolute material paths to relative paths - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialTypeSourcePath.c_str(), info, watchFolder); - if (!result) + if (!editData.m_materialTypeSourcePath.empty()) { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get material type source file info while attempting to export: %s", path.c_str()); - return false; - } + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + editData.m_materialTypeSourcePath.c_str(), info, watchFolder); + if (!result) + { + AZ_Error( + "AZ::Render::EditorMaterialComponentUtil", false, + "Failed to get material type source file info while attempting to export: %s", path.c_str()); + return false; + } - exportData.m_materialType = info.m_relativePath; + exportData.m_materialType = + AZ::IO::PathView(editData.m_materialTypeSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + } if (!editData.m_materialParentSourcePath.empty()) { - result = false; + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; AzToolsFramework::AssetSystemRequestBus::BroadcastResult( result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, editData.m_materialParentSourcePath.c_str(), info, watchFolder); @@ -131,17 +141,19 @@ namespace AZ return false; } - exportData.m_parentMaterial = info.m_relativePath; + exportData.m_parentMaterial = + AZ::IO::PathView(editData.m_materialParentSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); } // Copy all of the properties from the material asset to the source data that will be exported - result = true; - editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + bool result = true; + editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){ const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyIndex propertyIndex = editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); - AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; + AZ::RPI::MaterialPropertyValue propertyValue = + editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value; if (editData.m_materialParentAsset.IsReady()) @@ -151,12 +163,12 @@ namespace AZ // Check for and apply any property overrides before saving property values auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); - if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) + if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; From 84ca17e7cb91faae5e73dbc12ab4ff2a41073410 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 22:49:14 -0500 Subject: [PATCH 172/200] =?UTF-8?q?=EF=BB=BFCreated=20function=20to=20get?= =?UTF-8?q?=20relative=20paths=20to=20referenced=20files=20that=20will=20f?= =?UTF-8?q?all=20back=20to=20asset=20folder=20relative=20paths=20under=20c?= =?UTF-8?q?ertain=20conditions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../Util/MaterialPropertyUtil.h | 14 ++++- .../Code/Source/Util/MaterialPropertyUtil.cpp | 46 ++++++++++++++++- .../Code/Source/Document/MaterialDocument.cpp | 51 ++++++++----------- .../Code/Source/Document/MaterialDocument.h | 4 +- .../Material/EditorMaterialComponentUtil.cpp | 11 ++-- 5 files changed, 84 insertions(+), 42 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index d888c76553..b191e01bce 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -45,10 +45,22 @@ namespace AtomToolsFramework //! Convert the property value into the format that will be stored in the source data //! This is primarily needed to support conversions of special types like enums and images bool ConvertToExportFormat( - const AZ::IO::BasicPath& exportFolder, + const AZStd::string& exportPath, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue); + //! Generate a file path from the exported file to the external reference. + //! This function is to support copying or moving a folder containing materials, models, and textures without modifying the files. The + //! general case returns a relative path from the export file to the reference file. If the reference path is too different or distant + //! from the export path then it might be more difficult to work with than an asset folder relative path. For example, material types + //! that Atom provides live in a folder that should be accessible from anywhere. When materials are created in arbitrary gems and + //! project folders, a relative path to the material type would need to be updated whenever the materials are copied or moved. The same + //! thing will happen with parent materials or textures if their paths can’t be resolved. To alleviate some of this, we use the asset + //! folder relative path if the export folder relative path is too complex. An alternate solution would be to only use export folder + //! relative paths if the referenced path is in the same folder or a sub folder the assets are not generally packaged like that. + AZStd::string GetExteralReferencePath( + const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); + //! Traverse up the instance data node hierarchy to find the containing dynamic property object const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode); } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index b142977049..6ad9506fdd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -166,10 +166,13 @@ namespace AtomToolsFramework } bool ConvertToExportFormat( - const AZ::IO::BasicPath& exportFolder, + const AZStd::string& exportPath, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue) { + AZ::IO::BasicPath exportFolder(exportPath); + exportFolder.RemoveFilename(); + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) { const uint32_t index = propertyValue.GetValue(); @@ -206,6 +209,47 @@ namespace AtomToolsFramework return true; } + AZStd::string GetExteralReferencePath(const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth) + { + if (referencePath.empty()) + { + return {}; + } + + AZ::IO::BasicPath exportFolder(exportPath); + exportFolder.RemoveFilename(); + + const AZStd::string relativePath = AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix(); + + // Count the difference in depth between the export file path and the referenced file path. + uint32_t parentFolderCount = 0; + AZStd::string::size_type pos = 0; + const AZStd::string parentFolderToken = ".."; + while ((pos = relativePath.find(parentFolderToken, pos)) != AZStd::string::npos) + { + parentFolderCount++; + pos += parentFolderToken.length(); + } + + // If the difference in depth is too great then revert to using the asset folder relative path. + // We could change this to only use relative paths for references in subfolders. + if (parentFolderCount > maxPathDepth) + { + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(), + assetInfo, watchFolder); + if (sourceInfoFound) + { + return assetInfo.m_relativePath; + } + } + + return relativePath; + } + const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode) { // Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index ac07560d71..01d06537c4 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -228,18 +228,15 @@ namespace MaterialEditor return false; } - AZ::IO::BasicPath exportFolder(m_absolutePath); - exportFolder.RemoveFilename(); - // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; - sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); - sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_materialType); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties const bool savedProperties = SavePropertiesToSourceData( - exportFolder, sourceData, + m_absolutePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); @@ -302,18 +299,16 @@ namespace MaterialEditor return false; } - AZ::IO::BasicPath exportFolder(normalizedSavePath); - exportFolder.RemoveFilename(); - // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; - sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); - sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); + sourceData.m_parentMaterial = + AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties const bool savedProperties = SavePropertiesToSourceData( - exportFolder, sourceData, + normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); @@ -375,27 +370,21 @@ namespace MaterialEditor return false; } - AZ::IO::BasicPath exportFolder(normalizedSavePath); - exportFolder.RemoveFilename(); - // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; - sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = AZ::IO::PathView(m_absolutePath).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_parentMaterial = + AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); } - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); - // populate sourceData with modified properties const bool savedProperties = SavePropertiesToSourceData( - exportFolder, sourceData, + normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); @@ -595,9 +584,7 @@ namespace MaterialEditor } bool MaterialDocument::SavePropertiesToSourceData( - const AZ::IO::BasicPath& exportFolder, - AZ::RPI::MaterialSourceData& sourceData, - PropertyFilterFunction propertyFilter) const + const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const { using namespace AZ; using namespace RPI; @@ -615,7 +602,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); result = false; @@ -700,6 +687,12 @@ namespace MaterialEditor return false; } m_materialTypeSourceData = materialTypeOutcome.GetValue(); + + if (MaterialSourceData::ApplyVersionUpdatesResult::Failed == m_materialSourceData.ApplyVersionUpdates(m_absolutePath)) + { + AZ_Error("MaterialDocument", false, "Material source data could not be auto updated to the latest version of the material type: '%s'.", m_materialSourceData.m_materialType.c_str()); + return false; + } } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index 7783ea2ba7..14538ba867 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -111,9 +111,7 @@ namespace MaterialEditor ////////////////////////////////////////////////////////////////////////// bool SavePropertiesToSourceData( - const AZ::IO::BasicPath& exportFolder, - AZ::RPI::MaterialSourceData& sourceData, - PropertyFilterFunction propertyFilter) const; + const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index c775676e68..8dc6da077e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -98,9 +98,6 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { - AZ::IO::BasicPath exportFolder(path); - exportFolder.RemoveFilename(); - // Construct the material source data object that will be exported AZ::RPI::MaterialSourceData exportData; @@ -121,8 +118,7 @@ namespace AZ return false; } - exportData.m_materialType = - AZ::IO::PathView(editData.m_materialTypeSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); } if (!editData.m_materialParentSourcePath.empty()) @@ -141,8 +137,7 @@ namespace AZ return false; } - exportData.m_parentMaterial = - AZ::IO::PathView(editData.m_materialParentSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); } // Copy all of the properties from the material asset to the source data that will be exported @@ -168,7 +163,7 @@ namespace AZ propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(path, propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; From b643a8c80fd1897442bdca8b37a36d00cf2176d2 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 22:55:07 -0500 Subject: [PATCH 173/200] updated comment Signed-off-by: Guthrie Adams --- .../AtomToolsFramework/Util/MaterialPropertyUtil.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index b191e01bce..0c1ab08b24 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -51,12 +51,8 @@ namespace AtomToolsFramework //! Generate a file path from the exported file to the external reference. //! This function is to support copying or moving a folder containing materials, models, and textures without modifying the files. The - //! general case returns a relative path from the export file to the reference file. If the reference path is too different or distant - //! from the export path then it might be more difficult to work with than an asset folder relative path. For example, material types - //! that Atom provides live in a folder that should be accessible from anywhere. When materials are created in arbitrary gems and - //! project folders, a relative path to the material type would need to be updated whenever the materials are copied or moved. The same - //! thing will happen with parent materials or textures if their paths can’t be resolved. To alleviate some of this, we use the asset - //! folder relative path if the export folder relative path is too complex. An alternate solution would be to only use export folder + //! general case returns a relative path from the export file to the reference file. If the relative path is too different or distant + //! from the export path then we return the asset folder relative path. An alternate solution would be to only use export folder //! relative paths if the referenced path is in the same folder or a sub folder the assets are not generally packaged like that. AZStd::string GetExteralReferencePath( const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); From ebcefb2fe7da2c5eae6ee02fe15134c8404b52cd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 23:08:16 -0500 Subject: [PATCH 174/200] updated image paths to use new function Signed-off-by: Guthrie Adams --- .../Code/Source/Util/MaterialPropertyUtil.cpp | 11 +++--- .../Code/Source/Document/MaterialDocument.cpp | 36 ++++++++----------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 6ad9506fdd..c49cd3fafb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -170,9 +170,6 @@ namespace AtomToolsFramework const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue) { - AZ::IO::BasicPath exportFolder(exportPath); - exportFolder.RemoveFilename(); - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) { const uint32_t index = propertyValue.GetValue(); @@ -192,16 +189,16 @@ namespace AtomToolsFramework if (propertyValue.Is>()) { const auto& imageAsset = propertyValue.GetValue>(); - const auto& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); - propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); + propertyValue = GetExteralReferencePath(exportPath, imagePath); return true; } if (propertyValue.Is>()) { const auto& image = propertyValue.GetValue>(); - const auto& sourcePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; - propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + const auto& imagePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; + propertyValue = GetExteralReferencePath(exportPath, imagePath); return true; } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 01d06537c4..5f220da4b7 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -235,12 +235,10 @@ namespace MaterialEditor sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData( - m_absolutePath, sourceData, - [](const AtomToolsFramework::DynamicProperty& property) - { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData(m_absolutePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -303,16 +301,13 @@ namespace MaterialEditor MaterialSourceData sourceData; sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); - sourceData.m_parentMaterial = - AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData( - normalizedSavePath, sourceData, - [](const AtomToolsFramework::DynamicProperty& property) - { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -378,17 +373,14 @@ namespace MaterialEditor // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = - AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_absolutePath); } // populate sourceData with modified properties - const bool savedProperties = SavePropertiesToSourceData( - normalizedSavePath, sourceData, - [](const AtomToolsFramework::DynamicProperty& property) - { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); - }); + const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); + }); if (!savedProperties) { From 6d896beb4bb27aef9b73a2754dac134526e6a7bd Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 23:28:15 -0500 Subject: [PATCH 175/200] added version to material component exporter deleted unnecessary checks Signed-off-by: Guthrie Adams --- .../Material/EditorMaterialComponentUtil.cpp | 47 ++++--------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index 8dc6da077e..0fd7b7164d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -98,47 +98,18 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { - // Construct the material source data object that will be exported - AZ::RPI::MaterialSourceData exportData; - - // Converting absolute material paths to relative paths - if (!editData.m_materialTypeSourcePath.empty()) + if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() || + editData.m_materialTypeSourcePath.empty()) { - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialTypeSourcePath.c_str(), info, watchFolder); - if (!result) - { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get material type source file info while attempting to export: %s", path.c_str()); - return false; - } - - exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); + AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str()); + return false; } - if (!editData.m_materialParentSourcePath.empty()) - { - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialParentSourcePath.c_str(), info, watchFolder); - if (!result) - { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get parent material source file info while attempting to export: %s", path.c_str()); - return false; - } - - exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); - } + // Construct the material source data object that will be exported + AZ::RPI::MaterialSourceData exportData; + exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion(); + exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); + exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); // Copy all of the properties from the material asset to the source data that will be exported bool result = true; From b14e0958ce204a47e4e949c176bd8545bcdad895 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 1 Nov 2021 20:33:21 -0500 Subject: [PATCH 176/200] updated comments Signed-off-by: Guthrie Adams --- .../AtomToolsFramework/Util/MaterialPropertyUtil.h | 14 +++++++++----- .../Code/Source/Document/MaterialDocument.cpp | 12 +++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index 0c1ab08b24..08f59f9e0b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -36,7 +36,7 @@ namespace AtomToolsFramework //! Convert and assign material property meta data fields to editor dynamic property configuration void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData); - //! Convert and assign editor dynamic property configuration fields to material property meta data + //! Convert and assign editor dynamic property configuration fields to material property meta data void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig); //! Compare equality of data types and values of editor property stored in AZStd::any @@ -44,16 +44,20 @@ namespace AtomToolsFramework //! Convert the property value into the format that will be stored in the source data //! This is primarily needed to support conversions of special types like enums and images + //! @param exportPath absolute path of the file being saved + //! @param propertyDefinition describes type information and other details about propertyValue + //! @param propertyValue the value being converted before saving bool ConvertToExportFormat( const AZStd::string& exportPath, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue); //! Generate a file path from the exported file to the external reference. - //! This function is to support copying or moving a folder containing materials, models, and textures without modifying the files. The - //! general case returns a relative path from the export file to the reference file. If the relative path is too different or distant - //! from the export path then we return the asset folder relative path. An alternate solution would be to only use export folder - //! relative paths if the referenced path is in the same folder or a sub folder the assets are not generally packaged like that. + //! This function returns a relative path from the export file to the reference file. + //! If the relative path is too different or distant from the export path then we return the asset folder relative path. + //! @param exportPath absolute path of the file being saved + //! @param referencePath absolute path of a file that will be treated as an external reference + //! @param maxPathDepth the maximum relative depth or number of parent or child folders between the export path and the reference path AZStd::string GetExteralReferencePath( const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 5f220da4b7..26c2a6145e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -659,8 +659,8 @@ namespace MaterialEditor return false; } - // We must also always load the material type data for a complete, ordered set of the - // groups and properties that will be needed for comparison and building the inspector + // We always need the absolute path for the material type and parent material to load source data and resolving + // relative paths when saving. This will convert and store them as absolute paths for use within the document. if (!m_materialSourceData.m_parentMaterial.empty()) { m_materialSourceData.m_parentMaterial = @@ -672,6 +672,7 @@ namespace MaterialEditor m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); } + // Load the material type source data which provides the layout and default values of all of the properties auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); if (!materialTypeOutcome.IsSuccess()) { @@ -688,7 +689,9 @@ namespace MaterialEditor } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { - // Load the material type source data, which will be used for enumerating properties and building material source data + // A material document can be created or loaded from material or material type source data. If we are attempting to load + // material type source data then the material source data object can be created just by referencing the document path as the + // material type path. auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); if (!materialTypeOutcome.IsSuccess()) { @@ -697,8 +700,7 @@ namespace MaterialEditor } m_materialTypeSourceData = materialTypeOutcome.GetValue(); - // The document represents a material, not a material type. - // If the input data is a material type file we have to generate the material source data by referencing it. + // We are storing absolute paths in the loaded version of the source data so that the files can be resolved at all times. m_materialSourceData.m_materialType = m_absolutePath; m_materialSourceData.m_parentMaterial.clear(); } From bb4fdc8fe86c674fe02429832843bbf95e116a67 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 3 Nov 2021 14:02:21 -0500 Subject: [PATCH 177/200] Added basic unit test for relative path function Moved asset system stub to RPI utils Signed-off-by: Guthrie Adams --- Gems/Atom/RPI/Code/CMakeLists.txt | 1 + .../RPI/Code/Tests/Common/RPITestFixture.h | 2 +- Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake | 2 - .../AtomToolsFramework/Code/CMakeLists.txt | 28 +++++++ .../Code/Tests/AtomToolsFrameworkTest.cpp | 74 +++++++++++++++---- .../Code/atomtoolsframework_tests_files.cmake | 11 +++ Gems/Atom/Utils/Code/CMakeLists.txt | 21 ++++++ .../Include/Atom/Utils}/AssetSystemStub.h | 0 .../Code/Source}/AssetSystemStub.cpp | 2 +- .../Utils/Code/atom_utils_editor_files.cmake | 12 +++ 10 files changed, 135 insertions(+), 18 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake rename Gems/Atom/{RPI/Code/Tests/Common => Utils/Code/Include/Atom/Utils}/AssetSystemStub.h (100%) rename Gems/Atom/{RPI/Code/Tests/Common => Utils/Code/Source}/AssetSystemStub.cpp (99%) create mode 100644 Gems/Atom/Utils/Code/atom_utils_editor_files.cmake diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index 521178be20..7bf47d675a 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -160,6 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_RHI.Public Gem::Atom_RPI.Edit + Gem::Atom_Utils.Editor.Static ) ly_add_googletest( NAME Gem::Atom_RPI.Tests diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h index 48d404d268..b745e55ee8 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace UnitTest { diff --git a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake index e99e4e456b..5d67948ac8 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake @@ -10,8 +10,6 @@ set(FILES Tests/Buffer/BufferTests.cpp Tests/Common/AssetManagerTestFixture.cpp Tests/Common/AssetManagerTestFixture.h - Tests/Common/AssetSystemStub.cpp - Tests/Common/AssetSystemStub.h Tests/Common/ErrorMessageFinder.cpp Tests/Common/ErrorMessageFinder.h Tests/Common/ErrorMessageFinderTests.cpp diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index e64c9b80e7..bb2ac1f513 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -61,3 +61,31 @@ ly_add_target( PRIVATE Gem::AtomToolsFramework.Static ) + +################################################################################ +# Tests +################################################################################ +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + + ly_add_target( + NAME AtomToolsFramework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + atomtoolsframework_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + . + Tests + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzTestShared + Gem::AtomToolsFramework.Static + Gem::Atom_Utils.Editor.Static + ) + + ly_add_googletest( + NAME Gem::AtomToolsFramework.Tests + ) + +endif() \ No newline at end of file diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp index aee8e2a775..349c2b9ced 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp @@ -7,25 +7,71 @@ */ #include +#include +#include -class AtomToolsFrameworkTest - : public ::testing::Test +namespace UnitTest { -protected: - void SetUp() override + class AtomToolsFrameworkTest : public ::testing::Test { + protected: + void SetUp() override + { + if (!AZ::AllocatorInstance::IsReady()) + { + AZ::AllocatorInstance::Create(AZ::SystemAllocator::Descriptor()); + } - } + m_assetSystemStub.Activate(); - void TearDown() override - { + RegisterSourceAsset("objects/upgrades/materials/supercondor.material"); + RegisterSourceAsset("materials/condor.material"); + RegisterSourceAsset("materials/talisman.material"); + RegisterSourceAsset("materials/city.material"); + RegisterSourceAsset("materials/totem.material"); + RegisterSourceAsset("textures/orange.png"); + RegisterSourceAsset("textures/red.png"); + RegisterSourceAsset("textures/gold.png"); + RegisterSourceAsset("textures/fuzz.png"); + } - } -}; + void TearDown() override + { + m_assetSystemStub.Deactivate(); -TEST_F(AtomToolsFrameworkTest, SanityTest) -{ - ASSERT_TRUE(true); -} + if (AZ::AllocatorInstance::IsReady()) + { + AZ::AllocatorInstance::Destroy(); + } + } + + void RegisterSourceAsset(const AZStd::string& path) + { + const AZ::IO::BasicPath assetRootPath = AZ::IO::PathView(m_assetRoot).LexicallyNormal(); + const AZ::IO::BasicPath normalizedPath = AZ::IO::BasicPath(assetRootPath).Append(path).LexicallyNormal(); + + AZ::Data::AssetInfo assetInfo = {}; + assetInfo.m_assetId = AZ::Uuid::CreateRandom(); + assetInfo.m_relativePath = normalizedPath.LexicallyRelative(assetRootPath).StringAsPosix(); + m_assetSystemStub.RegisterSourceInfo(normalizedPath.StringAsPosix().c_str(), assetInfo, assetRootPath.StringAsPosix().c_str()); + } + + static constexpr const char* m_assetRoot = "d:/project/assets/"; + AssetSystemStub m_assetSystemStub; + }; + + TEST_F(AtomToolsFrameworkTest, GetExteralReferencePath_Succeeds) + { + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/condor.material", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 2), "../textures/gold.png"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 0), "textures/gold.png"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 3), "../../../materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 2), "materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 1), "materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 0), "materials/condor.material"); + } -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); + AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +} // namespace UnitTest diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake new file mode 100644 index 0000000000..bd9ad9b3d8 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake @@ -0,0 +1,11 @@ +# +# 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 + Tests/AtomToolsFrameworkTest.cpp +) \ No newline at end of file diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 89bc8dd0a5..cbdfb016a1 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -27,6 +27,27 @@ ly_add_target( 3rdParty::libpng ) +if(PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_target( + NAME Atom_Utils.Editor.Static STATIC + NAMESPACE Gem + FILES_CMAKE + atom_utils_editor_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AtomCore + AZ::AzCore + AZ::AzFramework + AZ::AzToolsFramework + ) +endif() + ################################################################################ # Tests ################################################################################ diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h similarity index 100% rename from Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h rename to Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp b/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp similarity index 99% rename from Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp rename to Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp index 31a46e9a6f..f026e8bcd7 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp +++ b/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake new file mode 100644 index 0000000000..7d7eb10e7c --- /dev/null +++ b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake @@ -0,0 +1,12 @@ +# +# 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 + Include/Atom/Utils/AssetSystemStub.h + Source/AssetSystemStub.cpp +) From 9522945f2067ca905d42fffcb118765f4afdf8dc Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 3 Nov 2021 17:28:12 -0500 Subject: [PATCH 178/200] moved AssetSystemStub to TestUtils folder Signed-off-by: Guthrie Adams --- Gems/Atom/RPI/Code/CMakeLists.txt | 2 +- Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h | 2 +- Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt | 2 +- .../AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp | 2 +- Gems/Atom/Utils/Code/CMakeLists.txt | 2 +- .../Code/Include/Atom/Utils/{ => TestUtils}/AssetSystemStub.h | 0 .../Utils/Code/Source/{ => TestUtils}/AssetSystemStub.cpp | 2 +- Gems/Atom/Utils/Code/atom_utils_editor_files.cmake | 4 ++-- 8 files changed, 8 insertions(+), 8 deletions(-) rename Gems/Atom/Utils/Code/Include/Atom/Utils/{ => TestUtils}/AssetSystemStub.h (100%) rename Gems/Atom/Utils/Code/Source/{ => TestUtils}/AssetSystemStub.cpp (98%) diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index 7bf47d675a..f0459a23c2 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -160,7 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_RHI.Public Gem::Atom_RPI.Edit - Gem::Atom_Utils.Editor.Static + Gem::Atom_Utils.TestUtils.Static ) ly_add_googletest( NAME Gem::Atom_RPI.Tests diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h index b745e55ee8..0707528d7f 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace UnitTest { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index bb2ac1f513..40c8d7956e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -81,7 +81,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest AZ::AzTestShared Gem::AtomToolsFramework.Static - Gem::Atom_Utils.Editor.Static + Gem::Atom_Utils.TestUtils.Static ) ly_add_googletest( diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp index 349c2b9ced..df16cfbc43 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp @@ -7,7 +7,7 @@ */ #include -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index cbdfb016a1..90d7ce501b 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -30,7 +30,7 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Atom_Utils.Editor.Static STATIC + NAME Atom_Utils.TestUtils.Static STATIC NAMESPACE Gem FILES_CMAKE atom_utils_editor_files.cmake diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/TestUtils/AssetSystemStub.h similarity index 100% rename from Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h rename to Gems/Atom/Utils/Code/Include/Atom/Utils/TestUtils/AssetSystemStub.h diff --git a/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp b/Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp similarity index 98% rename from Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp rename to Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp index f026e8bcd7..d57969ea9c 100644 --- a/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp +++ b/Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake index 7d7eb10e7c..6c4202fe09 100644 --- a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake +++ b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake @@ -7,6 +7,6 @@ # set(FILES - Include/Atom/Utils/AssetSystemStub.h - Source/AssetSystemStub.cpp + Include/Atom/Utils/TestUtils/AssetSystemStub.h + Source/TestUtils/AssetSystemStub.cpp ) From f041661474374ff7ecf86ef63728c080dfef9308 Mon Sep 17 00:00:00 2001 From: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> Date: Wed, 3 Nov 2021 18:45:35 -0400 Subject: [PATCH 179/200] Correcting system requirements for the startup Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.com> --- .../Gem/Code/Source/AutomatedTestingSystemComponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp b/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp index a77f62caf2..06a0775d70 100644 --- a/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp +++ b/AutomatedTesting/Gem/Code/Source/AutomatedTestingSystemComponent.cpp @@ -46,7 +46,7 @@ namespace AutomatedTesting void AutomatedTestingSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - AZ_UNUSED(required); + required.push_back(AZ_CRC_CE("MultiplayerService")); } void AutomatedTestingSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent) From 68e2770caf46e6755eb87ad617c3d914f8343ccb Mon Sep 17 00:00:00 2001 From: Sean Masterson Date: Wed, 3 Nov 2021 15:52:39 -0700 Subject: [PATCH 180/200] Adding P0 Automation for HDR Color Grading Component Signed-off-by: Sean Masterson --- .../Atom/TestSuite_Main_Optimized.py | 4 + .../Atom/atom_utils/atom_constants.py | 1 + ...omEditorComponents_HDRColorGradingAdded.py | 192 ++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index e2a45f9928..950bd44199 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -42,6 +42,10 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_GridAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module + @pytest.mark.test_case_id("C36525671") + class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module + @pytest.mark.test_case_id("C32078117") class AtomEditorComponents_LightAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index 344a0dbd29..c365999335 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -218,6 +218,7 @@ class AtomComponentProperties: properties = { 'name': 'HDR Color Grading', 'requires': [AtomComponentProperties.postfx_layer()], + 'Enable HDR color grading': 'Controller|Configuration|Enable HDR color grading', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py new file mode 100644 index 0000000000..4972079fcd --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py @@ -0,0 +1,192 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +class Tests: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + hdr_color_grading_creation = ( + "HDR Color Grading Entity successfully created", + "HDR Color Grading Entity failed to be created") + hdr_color_grading_component = ( + "Entity has an HDR Color Grading component", + "Entity failed to find HDR Color Grading component") + hdr_color_grading_disabled = ( + "HDR Color Grading component disabled", + "HDR Color Grading component was not disabled") + postfx_layer_component = ( + "Entity has a PostFX Layer component", + "Entity did not have an PostFX Layer component") + hdr_color_grading_enabled = ( + "HDR Color Grading component enabled", + "HDR Color Grading component was not enabled") + enable_hdr_color_grading_parameter_enabled = ( + "Enable HDR Color Grading parameter enabled", + "Enable HDR Color Grading parameter was not enabled") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_HDRColorGrading_AddedToEntity(): + """ + Summary: + Tests the HDR Color Grading component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create an HDR Color Grading entity with no components. + 2) Add HDR Color Grading component to HDR Color Grading entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify HDR Color Grading component not enabled. + 6) Add PostFX Layer component since it is required by the HDR Color Grading component. + 7) Verify HDR Color Grading component is enabled. + 8) Enable the "Enable HDR Color Grading" parameter. + 9) Enter/Exit game mode. + 10) Test IsHidden. + 11) Test IsVisible. + 12) Delete HDR Color Grading entity. + 13) UNDO deletion. + 14) REDO deletion. + 15) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create an HDR Color Grading entity with no components. + hdr_color_grading_entity = EditorEntity.create_editor_entity(AtomComponentProperties.hdr_color_grading()) + Report.critical_result(Tests.hdr_color_grading_creation, hdr_color_grading_entity.exists()) + + # 2. Add HDR Color Grading component to HDR Color Grading entity. + hdr_color_grading_component = hdr_color_grading_entity.add_component( + AtomComponentProperties.hdr_color_grading()) + Report.critical_result( + Tests.hdr_color_grading_component, + hdr_color_grading_entity.has_component(AtomComponentProperties.hdr_color_grading())) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not hdr_color_grading_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, hdr_color_grading_entity.exists()) + + # 5. Verify HDR Color Grading component not enabled. + Report.result(Tests.hdr_color_grading_disabled, not hdr_color_grading_component.is_enabled()) + + # 6. Add PostFX Layer component since it is required by the HDR Color Grading component. + hdr_color_grading_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result( + Tests.postfx_layer_component, + hdr_color_grading_entity.has_component(AtomComponentProperties.postfx_layer())) + + # 7. Verify HDR Color Grading component is enabled. + Report.result(Tests.hdr_color_grading_enabled, hdr_color_grading_component.is_enabled()) + + # 8. Enable the "Enable HDR Color Grading" parameter. + hdr_color_grading_component.set_component_property_value( + AtomComponentProperties.hdr_color_grading('Enable HDR color grading'), True) + Report.result(Tests.enable_hdr_color_grading_parameter_enabled, + hdr_color_grading_component.get_component_property_value( + AtomComponentProperties.hdr_color_grading('Enable HDR color grading')) is True) + + # 9. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 10. Test IsHidden. + hdr_color_grading_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, hdr_color_grading_entity.is_hidden() is True) + + # 11. Test IsVisible. + hdr_color_grading_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, hdr_color_grading_entity.is_visible() is True) + + # 12. Delete HDR Color Grading entity. + hdr_color_grading_entity.delete() + Report.result(Tests.entity_deleted, not hdr_color_grading_entity.exists()) + + # 13. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, hdr_color_grading_entity.exists()) + + # 14. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not hdr_color_grading_entity.exists()) + + # 15. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomEditorComponents_HDRColorGrading_AddedToEntity) From 618a65e7dde55b5b82b785fa9ee9d0e0b554137c Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Wed, 3 Nov 2021 15:56:03 -0700 Subject: [PATCH 181/200] indexBuffer reserve amount seems off. (#5268) Signed-off-by: rhhong --- .../Code/Source/AuxGeom/AuxGeomDrawQueue.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp index 29db7d6673..b755a6efee 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp @@ -659,16 +659,17 @@ namespace AZ AuxGeomIndex vertexOffset = aznumeric_cast(primBuffer.m_vertexBuffer.size()); AuxGeomIndex indexOffset = aznumeric_cast(primBuffer.m_indexBuffer.size()); + const size_t vertexCountTotal = aznumeric_cast(vertexOffset) + vertexCount; - if (aznumeric_cast(vertexOffset) + vertexCount > MaxDynamicVertexCount) + if (vertexCountTotal > MaxDynamicVertexCount) { AZ_WarningOnce("AuxGeom", false, "Draw function ignored, would exceed maximum allowed index of %d", MaxDynamicVertexCount); return; } AZ::Vector3 center(0.0f, 0.0f, 0.0f); - primBuffer.m_vertexBuffer.reserve(vertexCount); - primBuffer.m_indexBuffer.reserve(vertexCount); + primBuffer.m_vertexBuffer.reserve(vertexCountTotal); + primBuffer.m_indexBuffer.reserve(vertexCountTotal); for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) { AZ::u32 packedColor = packedColorFunction(vertexIndex); @@ -734,15 +735,16 @@ namespace AZ AuxGeomIndex vertexOffset = aznumeric_cast(primBuffer.m_vertexBuffer.size()); AuxGeomIndex indexOffset = aznumeric_cast(primBuffer.m_indexBuffer.size()); + const size_t vertexCountTotal = aznumeric_cast(vertexOffset) + vertexCount; - if (aznumeric_cast(vertexOffset) + vertexCount > MaxDynamicVertexCount) + if (vertexCountTotal > MaxDynamicVertexCount) { AZ_WarningOnce("AuxGeom", false, "Draw function ignored, would exceed maximum allowed index of %d", MaxDynamicVertexCount); return; } AZ::Vector3 center(0.0f, 0.0f, 0.0f); - primBuffer.m_vertexBuffer.reserve(vertexCount); + primBuffer.m_vertexBuffer.reserve(vertexCountTotal); for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) { AZ::u32 packedColor = packedColorFunction(vertexIndex); @@ -753,7 +755,7 @@ namespace AZ } center /= aznumeric_cast(vertexCount); - primBuffer.m_indexBuffer.reserve(indexCount); + primBuffer.m_indexBuffer.reserve(indexCount + indexOffset); for (uint32_t index = 0; index < indexCount; ++index) { primBuffer.m_indexBuffer.push_back(vertexOffset + indexFunction(index)); From 54506b6c6ce380098dd8cfad45f0c541409f6143 Mon Sep 17 00:00:00 2001 From: Benjamin Jillich <43751992+amzn-jillich@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:52:27 +0100 Subject: [PATCH 182/200] Animation Editor: Clicking Visualization in Anim Graph in the animation editor has no effect. (#5088) asprintf() is returning a new QString and is also deprecated. Switched to use the AZStd::string::format() as that uses the small string optimization and doesn't result in an allocation. Resolves #2429 Signed-off-by: Benjamin Jillich --- .../StandardPlugins/Source/AnimGraph/NodeGraph.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp index 49b986887c..e97ff19113 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/StandardPlugins/Source/AnimGraph/NodeGraph.cpp @@ -6,7 +6,8 @@ * */ -#include "AzCore/std/numeric.h" +#include +#include #include #include #include @@ -231,7 +232,7 @@ namespace EMStudio // add the playspeed if (plugin->GetIsDisplayFlagEnabled(AnimGraphPlugin::DISPLAYFLAG_PLAYSPEED)) { - m_qtTempString.asprintf("Play Speed = %.2f", emfxNode->GetPlaySpeed(animGraphInstance)); + m_qtTempString = AZStd::fixed_string<24>::format("Play Speed = %.2f", emfxNode->GetPlaySpeed(animGraphInstance)).c_str(); painter.drawText(textPosition, m_qtTempString); textPosition.setY(textPosition.y() + heightSpacing); } @@ -239,7 +240,7 @@ namespace EMStudio // add the global weight if (plugin->GetIsDisplayFlagEnabled(AnimGraphPlugin::DISPLAYFLAG_GLOBALWEIGHT)) { - m_qtTempString.asprintf("Global Weight = %.2f", uniqueData->GetGlobalWeight()); + m_qtTempString = AZStd::fixed_string<24>::format("Global Weight = %.2f", uniqueData->GetGlobalWeight()).c_str(); painter.drawText(textPosition, m_qtTempString); textPosition.setY(textPosition.y() + heightSpacing); } @@ -247,7 +248,7 @@ namespace EMStudio // add the sync if (plugin->GetIsDisplayFlagEnabled(AnimGraphPlugin::DISPLAYFLAG_SYNCSTATUS)) { - m_qtTempString.asprintf("Synced = %s", animGraphInstance->GetIsSynced(emfxNode->GetObjectIndex()) ? "Yes" : "No"); + m_qtTempString = AZStd::fixed_string<24>::format("Synced = %s", animGraphInstance->GetIsSynced(emfxNode->GetObjectIndex()) ? "Yes" : "No").c_str(); painter.drawText(textPosition, m_qtTempString); textPosition.setY(textPosition.y() + heightSpacing); } @@ -255,7 +256,7 @@ namespace EMStudio // add the play position if (plugin->GetIsDisplayFlagEnabled(AnimGraphPlugin::DISPLAYFLAG_PLAYPOSITION)) { - m_qtTempString.asprintf("Play Time = %.3f / %.3f", uniqueData->GetCurrentPlayTime(), uniqueData->GetDuration()); + m_qtTempString = AZStd::fixed_string<32>::format("Play Time = %.3f / %.3f", uniqueData->GetCurrentPlayTime(), uniqueData->GetDuration()).c_str(); painter.drawText(textPosition, m_qtTempString); textPosition.setY(textPosition.y() + heightSpacing); } From 891a4f6782566bfa991f2b94d86a3a806b5fd119 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 4 Nov 2021 08:22:20 -0700 Subject: [PATCH 183/200] bugfix: resolve crash with FBX Settings (#4813) (#4944) -prevent export of ModuleInitISystem and ModuleShutdownISystem Signed-off-by: Michael Pollind --- Code/Legacy/CryCommon/ISystem.h | 4 ++-- Code/Legacy/CryCommon/platform_impl.cpp | 4 ++-- Code/Legacy/CrySystem/SystemInit.cpp | 23 ----------------------- 3 files changed, 4 insertions(+), 27 deletions(-) diff --git a/Code/Legacy/CryCommon/ISystem.h b/Code/Legacy/CryCommon/ISystem.h index 948977d02a..dd29209b24 100644 --- a/Code/Legacy/CryCommon/ISystem.h +++ b/Code/Legacy/CryCommon/ISystem.h @@ -1121,8 +1121,8 @@ inline ISystem* GetISystem() // Description: // This function must be called once by each module at the beginning, to setup global pointers. -extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, const char* moduleName); -extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem(ISystem* pSystem); +void ModuleInitISystem(ISystem* pSystem, const char* moduleName); +void ModuleShutdownISystem(ISystem* pSystem); extern "C" AZ_DLL_EXPORT void InjectEnvironment(void* env); extern "C" AZ_DLL_EXPORT void DetachEnvironment(); diff --git a/Code/Legacy/CryCommon/platform_impl.cpp b/Code/Legacy/CryCommon/platform_impl.cpp index a68a5150db..845a1101a4 100644 --- a/Code/Legacy/CryCommon/platform_impl.cpp +++ b/Code/Legacy/CryCommon/platform_impl.cpp @@ -74,7 +74,7 @@ void InitCRTHandlers() {} ////////////////////////////////////////////////////////////////////////// // This is an entry to DLL initialization function that must be called for each loaded module ////////////////////////////////////////////////////////////////////////// -extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName) +void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName) { if (gEnv) // Already registered. { @@ -96,7 +96,7 @@ extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused } // if pSystem } -extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem) +void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem) { // Unregister with AZ environment. AZ::Environment::Detach(); diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index ac0683cf1b..99cc92ee6a 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -173,8 +173,6 @@ void CryEngineSignalHandler(int signal) ////////////////////////////////////////////////////////////////////////// #if defined(WIN32) || defined(LINUX) || defined(APPLE) -# define DLL_MODULE_INIT_ISYSTEM "ModuleInitISystem" -# define DLL_MODULE_SHUTDOWN_ISYSTEM "ModuleShutdownISystem" # define DLL_INITFUNC_RENDERER "PackageRenderConstructor" # define DLL_INITFUNC_SOUND "CreateSoundSystem" # define DLL_INITFUNC_FONT "CreateCryFontInterface" @@ -188,8 +186,6 @@ void CryEngineSignalHandler(int signal) #if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) #undef AZ_RESTRICTED_SECTION_IMPLEMENTED #else -# define DLL_MODULE_INIT_ISYSTEM (LPCSTR)2 -# define DLL_MODULE_SHUTDOWN_ISYSTEM (LPCSTR)3 # define DLL_INITFUNC_RENDERER (LPCSTR)1 # define DLL_INITFUNC_RENDERER (LPCSTR)1 # define DLL_INITFUNC_SOUND (LPCSTR)1 @@ -445,18 +441,6 @@ AZStd::unique_ptr CSystem::LoadDLL(const char* dllName) return handle; } - ////////////////////////////////////////////////////////////////////////// - // After loading DLL initialize it by calling ModuleInitISystem - ////////////////////////////////////////////////////////////////////////// - AZStd::string moduleName = PathUtil::GetFileName(dllName); - - typedef void*(*PtrFunc_ModuleInitISystem)(ISystem* pSystem, const char* moduleName); - PtrFunc_ModuleInitISystem pfnModuleInitISystem = handle->GetFunction(DLL_MODULE_INIT_ISYSTEM); - if (pfnModuleInitISystem) - { - pfnModuleInitISystem(this, moduleName.c_str()); - } - return handle; } @@ -497,13 +481,6 @@ void CSystem::ShutdownModuleLibraries() #if !defined(AZ_MONOLITHIC_BUILD) for (auto iterator = m_moduleDLLHandles.begin(); iterator != m_moduleDLLHandles.end(); ++iterator) { - typedef void*( * PtrFunc_ModuleShutdownISystem )(ISystem* pSystem); - - PtrFunc_ModuleShutdownISystem pfnModuleShutdownISystem = iterator->second->GetFunction(DLL_MODULE_SHUTDOWN_ISYSTEM); - if (pfnModuleShutdownISystem) - { - pfnModuleShutdownISystem(this); - } if (iterator->second->IsLoaded()) { iterator->second->Unload(); From 73202c209152645a304702f6c7e8d984ebd51dd4 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Thu, 4 Nov 2021 10:45:18 -0500 Subject: [PATCH 184/200] [LYN-7245] Fix test thread being created multiple times (#5267) * Fix test thread being created multiple times Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update test to not use a callback Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add some more comments Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add back the callback, remove the use of a thread/sleep Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../AssetProcessorManagerTest.cpp | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp index 5bcb6dc583..0cbdc20f1c 100644 --- a/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp +++ b/Code/Tools/AssetProcessor/native/tests/assetmanager/AssetProcessorManagerTest.cpp @@ -4140,11 +4140,19 @@ struct LockedFileTest switch (message.GetMessageType()) { case SourceFileNotificationMessage::MessageType: - if (const auto sourceFileMessage = azrtti_cast(&message); - sourceFileMessage != nullptr && sourceFileMessage->m_type == SourceFileNotificationMessage::NotificationType::FileRemoved - && m_callback) + if (const auto sourceFileMessage = azrtti_cast(&message); sourceFileMessage != nullptr && + sourceFileMessage->m_type == SourceFileNotificationMessage::NotificationType::FileRemoved) { - m_callback(); + // The File Remove message will occur before an attempt to delete the file + // Wait for more than 1 File Remove message. + // This indicates the AP has attempted to delete the file once, failed to do so and is now retrying + ++m_deleteCounter; + + if(m_deleteCounter > 1 && m_callback) + { + m_callback(); + m_callback = {}; // Unset it to be safe, we only intend to run the callback once + } } break; default: @@ -4168,6 +4176,7 @@ struct LockedFileTest ModtimeScanningTest::TearDown(); } + AZStd::atomic_int m_deleteCounter{ 0 }; AZStd::function m_callback; }; @@ -4207,6 +4216,10 @@ TEST_F(LockedFileTest, DeleteFile_LockedProduct_DeleteFails) TEST_F(LockedFileTest, DeleteFile_LockedProduct_DeletesWhenReleased) { + // This test is intended to verify the AP will successfully retry deleting a source asset + // when one of its product assets is locked temporarily + // We'll lock the file by holding it open + auto theFile = m_data->m_absolutePath[1].toUtf8(); const char* theFileString = theFile.constData(); auto [sourcePath, productPath] = *m_data->m_productPaths.find(theFileString); @@ -4219,19 +4232,22 @@ TEST_F(LockedFileTest, DeleteFile_LockedProduct_DeletesWhenReleased) ASSERT_GT(m_data->m_productPaths.size(), 0); QFile product(productPath); + // Open the file and keep it open to lock it + // We'll start a thread later to unlock the file + // This will allow us to test how AP handles trying to delete a locked file ASSERT_TRUE(product.open(QIODevice::ReadOnly)); // Check if we can delete the file now, if we can't, proceed with the test // If we can, it means the OS running this test doesn't lock open files so there's nothing to test if (!AZ::IO::SystemFile::Delete(productPath.toUtf8().constData())) { - AZStd::thread workerThread; + m_deleteCounter = 0; - m_callback = [&product, &workerThread]() { - workerThread = AZStd::thread([&product]() { - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(60)); - product.close(); - }); + // Set up a callback which will fire after at least 1 retry + // Unlock the file at that point so AP can successfully delete it + m_callback = [&product]() + { + product.close(); }; QMetaObject::invokeMethod( @@ -4241,8 +4257,9 @@ TEST_F(LockedFileTest, DeleteFile_LockedProduct_DeletesWhenReleased) EXPECT_FALSE(QFile::exists(productPath)); EXPECT_EQ(m_data->m_deletedSources.size(), 1); - - workerThread.join(); + + EXPECT_GT(m_deleteCounter, 1); // Make sure the AP tried more than once to delete the file + m_errorAbsorber->ExpectAsserts(0); } else { From 1470d97f58ecd3efc25ff0dc5efbf158ff55e422 Mon Sep 17 00:00:00 2001 From: Andre Mitchell <47983418+BytesOfPiDev@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:48:10 -0400 Subject: [PATCH 185/200] Remove virtual keyword. (#4992) SetupUI()is called in the AssetEditorMainWindow constructor - it should not be virtual. Derived classes will not receive the call. Signed-off-by: Andre Mitchell --- .../GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h index 139c540767..1c83fb7717 100644 --- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h +++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Widgets/GraphCanvasEditor/GraphCanvasAssetEditorMainWindow.h @@ -89,7 +89,7 @@ namespace GraphCanvas explicit AssetEditorMainWindow(AssetEditorWindowConfig* config, QWidget* parent = nullptr); virtual ~AssetEditorMainWindow(); - virtual void SetupUI(); + void SetupUI(); void SetDropAreaText(AZStd::string_view text); const EditorId& GetEditorId() const; From be7c8c8dd33a73c8cedf6fe20e72a1dc0cc9ca26 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 4 Nov 2021 09:55:59 -0700 Subject: [PATCH 186/200] Removing flaky multiplayer tests. Will bring back once we can reproduce and correct the flakes Signed-off-by: Gene Walters --- AutomatedTesting/Gem/PythonTests/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index bec49185bd..fd3222ba83 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -59,8 +59,5 @@ add_subdirectory(smoke) ## AWS ## add_subdirectory(AWS) -## Multiplayer ## -add_subdirectory(Multiplayer) - ## Integration tests for editor testing framework ## add_subdirectory(editor_test_testing) From 0b7bff79d36b15cf69c3d9ea1efc0dd415a17858 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 4 Nov 2021 10:10:29 -0700 Subject: [PATCH 187/200] Removes VTUNE profiler hooks from Cry (#5291) * Removes VTUNE profiler hooks from Cry Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * some more vtune cleanup Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Editor/CryEdit.cpp | 1 - Code/Editor/CryEditDoc.cpp | 16 ------- Code/Legacy/CryCommon/ISystem.h | 19 -------- Code/Legacy/CryCommon/Mocks/ISystemMock.h | 2 - Code/Legacy/CrySystem/System.cpp | 56 ----------------------- Code/Legacy/CrySystem/System.h | 25 ---------- Code/Legacy/CrySystem/SystemInit.cpp | 32 ------------- 7 files changed, 151 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index c5c3acd2f6..b47febd5ed 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -548,7 +548,6 @@ public: { "BatchMode", m_bConsoleMode }, { "NullRenderer", m_bNullRenderer }, { "devmode", m_bDeveloperMode }, - { "VTUNE", dummy }, { "runpython", m_bRunPythonScript }, { "runpythontest", m_bRunPythonTestScript }, { "version", m_bShowVersionInfo }, diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp index 4944c3bff5..212606c737 100644 --- a/Code/Editor/CryEditDoc.cpp +++ b/Code/Editor/CryEditDoc.cpp @@ -60,15 +60,6 @@ #include #include // for LmbrCentral::EditorLightComponentRequestBus -//#define PROFILE_LOADING_WITH_VTUNE - -// profilers api. -//#include "pure.h" -#ifdef PROFILE_LOADING_WITH_VTUNE -#include "C:\Program Files\Intel\Vtune\Analyzer\Include\VTuneApi.h" -#pragma comment(lib,"C:\\Program Files\\Intel\\Vtune\\Analyzer\\Lib\\VTuneApi.lib") -#endif - static const char* kAutoBackupFolder = "_autobackup"; static const char* kHoldFolder = "$tmp_hold"; // conform to the ignored file types $tmp[0-9]*_ regex static const char* kSaveBackupFolder = "_savebackup"; @@ -408,9 +399,6 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename) int t0 = GetTickCount(); -#ifdef PROFILE_LOADING_WITH_VTUNE - VTResume(); -#endif // Load level-specific audio data. AZStd::string levelFileName{ fileName.toUtf8().constData() }; AZStd::to_lower(levelFileName.begin(), levelFileName.end()); @@ -484,10 +472,6 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename) CSurfaceTypeValidator().Validate(); -#ifdef PROFILE_LOADING_WITH_VTUNE - VTPause(); -#endif - LogLoadTime(GetTickCount() - t0); // Loaded with success, remove event from log file GetIEditor()->GetSettingsManager()->UnregisterEvent(loadEvent); diff --git a/Code/Legacy/CryCommon/ISystem.h b/Code/Legacy/CryCommon/ISystem.h index dd29209b24..103e7b50c2 100644 --- a/Code/Legacy/CryCommon/ISystem.h +++ b/Code/Legacy/CryCommon/ISystem.h @@ -739,24 +739,6 @@ public: #undef GetUserName #endif - -struct IProfilingSystem -{ - // - virtual ~IProfilingSystem() {} - ////////////////////////////////////////////////////////////////////////// - // VTune Profiling interface. - - // Summary: - // Resumes vtune data collection. - virtual void VTuneResume() = 0; - // Summary: - // Pauses vtune data collection. - virtual void VTunePause() = 0; - ////////////////////////////////////////////////////////////////////////// - // -}; - //////////////////////////////////////////////////////////////////////////////////////////////// // Description: @@ -851,7 +833,6 @@ struct ISystem virtual IMovieSystem* GetIMovieSystem() = 0; virtual ::IConsole* GetIConsole() = 0; virtual IRemoteConsole* GetIRemoteConsole() = 0; - virtual IProfilingSystem* GetIProfilingSystem() = 0; virtual ISystemEventDispatcher* GetISystemEventDispatcher() = 0; virtual ITimer* GetITimer() = 0; diff --git a/Code/Legacy/CryCommon/Mocks/ISystemMock.h b/Code/Legacy/CryCommon/Mocks/ISystemMock.h index 9d41b9e77d..a11b60fe68 100644 --- a/Code/Legacy/CryCommon/Mocks/ISystemMock.h +++ b/Code/Legacy/CryCommon/Mocks/ISystemMock.h @@ -76,8 +76,6 @@ public: ::IConsole * ()); MOCK_METHOD0(GetIRemoteConsole, IRemoteConsole * ()); - MOCK_METHOD0(GetIProfilingSystem, - IProfilingSystem * ()); MOCK_METHOD0(GetISystemEventDispatcher, ISystemEventDispatcher * ()); MOCK_METHOD0(GetITimer, diff --git a/Code/Legacy/CrySystem/System.cpp b/Code/Legacy/CrySystem/System.cpp index 2e18e13841..eebe626918 100644 --- a/Code/Legacy/CrySystem/System.cpp +++ b/Code/Legacy/CrySystem/System.cpp @@ -143,9 +143,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include -// To enable profiling with vtune (https://software.intel.com/en-us/intel-vtune-amplifier-xe), make sure the line below is not commented out -//#define PROFILE_WITH_VTUNE - #include #include #endif @@ -154,10 +151,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include -// profilers api. -VTuneFunction VTResume = NULL; -VTuneFunction VTPause = NULL; - // Define global cvars. SSystemCVars g_cvars; @@ -697,31 +690,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode) m_bPaused = false; } -#ifdef PROFILE_WITH_VTUNE - if (m_bInDevMode) - { - if (VTPause != NULL && VTResume != NULL) - { - static bool bVtunePaused = true; - - const AzFramework::InputChannel* inputChannelScrollLock = AzFramework::InputChannelRequests::FindInputChannel(AzFramework::InputDeviceKeyboard::Key::WindowsSystemScrollLock); - const bool bPaused = (inputChannelScrollLock ? inputChannelScrollLock->IsActive() : false); - - { - if (bVtunePaused && !bPaused) - { - GetIProfilingSystem()->VTuneResume(); - } - if (!bVtunePaused && bPaused) - { - GetIProfilingSystem()->VTunePause(); - } - bVtunePaused = bPaused; - } - } - } -#endif //PROFILE_WITH_VTUNE - #ifndef EXCLUDE_UPDATE_ON_CONSOLE if (m_bIgnoreUpdates) { @@ -1255,30 +1223,6 @@ CPNoise3* CSystem::GetNoiseGen() return &m_pNoiseGen; } -////////////////////////////////////////////////////////////////////////// -void CProfilingSystem::VTuneResume() -{ -#ifdef PROFILE_WITH_VTUNE - if (VTResume) - { - CryLogAlways("VTune Resume"); - VTResume(); - } -#endif -} - -////////////////////////////////////////////////////////////////////////// -void CProfilingSystem::VTunePause() -{ -#ifdef PROFILE_WITH_VTUNE - if (VTPause) - { - VTPause(); - CryLogAlways("VTune Pause"); - } -#endif -} - ////////////////////////////////////////////////////////////////////// void CSystem::OnLanguageCVarChanged(ICVar* language) { diff --git a/Code/Legacy/CrySystem/System.h b/Code/Legacy/CrySystem/System.h index a3a0f12278..74ce1cbbc2 100644 --- a/Code/Legacy/CrySystem/System.h +++ b/Code/Legacy/CrySystem/System.h @@ -105,10 +105,6 @@ struct IDataProbe; #define PHSYICS_OBJECT_ENTITY 0 -using VTuneFunction = void (__cdecl *)(void); -extern VTuneFunction VTResume; -extern VTuneFunction VTPause; - #define MAX_STREAMING_POOL_INDEX 6 #define MAX_THREAD_POOL_INDEX 6 @@ -139,7 +135,6 @@ struct SSystemCVars int sys_ai; int sys_entitysystem; int sys_trackview; - int sys_vtune; float sys_update_profile_time; int sys_limit_phys_thread_count; int sys_MaxFPS; @@ -169,21 +164,6 @@ extern SSystemCVars g_cvars; class CSystem; -struct CProfilingSystem - : public IProfilingSystem -{ - ////////////////////////////////////////////////////////////////////////// - // VTune Profiling interface. - - // Summary: - // Resumes vtune data collection. - void VTuneResume() override; - // Summary: - // Pauses vtune data collection. - void VTunePause() override; - ////////////////////////////////////////////////////////////////////////// -}; - class AssetSystem; /* @@ -262,7 +242,6 @@ public: IViewSystem* GetIViewSystem() override; ILevelSystem* GetILevelSystem() override; ISystemEventDispatcher* GetISystemEventDispatcher() override { return m_pSystemEventDispatcher; } - IProfilingSystem* GetIProfilingSystem() override { return &m_ProfilingSystem; } ////////////////////////////////////////////////////////////////////////// // retrieves the perlin noise singleton instance CPNoise3* GetNoiseGen() override; @@ -564,8 +543,6 @@ private: // ------------------------------------------------------ ESystemConfigSpec m_nMaxConfigSpec; ESystemConfigPlatform m_ConfigPlatform; - CProfilingSystem m_ProfilingSystem; - // Pause mode. bool m_bPaused; bool m_bNoUpdate; @@ -588,8 +565,6 @@ public: const SFileVersion& GetProductVersion() override; const SFileVersion& GetBuildVersion() override; - bool InitVTuneProfiler(); - void OpenPlatformPaks(); void OpenLanguagePak(const char* sLanguage); void OpenLanguageAudioPak(const char* sLanguage); diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 99cc92ee6a..7ce9fcd342 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -70,9 +70,6 @@ #include "windows.h" #include -// To enable profiling with vtune (https://software.intel.com/en-us/intel-vtune-amplifier-xe), make sure the line below is not commented out -//#define PROFILE_WITH_VTUNE - #endif //WIN32 #include @@ -681,33 +678,6 @@ bool CSystem::InitAudioSystem(const SSystemInitParams& initParams) return result; } -////////////////////////////////////////////////////////////////////////// -bool CSystem::InitVTuneProfiler() -{ -#ifdef PROFILE_WITH_VTUNE - - WIN_HMODULE hModule = LoadDLL("VTuneApi.dll"); - if (!hModule) - { - return false; - } - - VTPause = (VTuneFunction) CryGetProcAddress(hModule, "VTPause"); - VTResume = (VTuneFunction) CryGetProcAddress(hModule, "VTResume"); - if (!VTPause || !VTResume) - { - AZ_Assert(false, "VTune did not initialize correctly.") - return false; - } - else - { - AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "VTune API Initialized"); - } -#endif //PROFILE_WITH_VTUNE - - return true; -} - ////////////////////////////////////////////////////////////////////////// void CSystem::InitLocalization() { @@ -1682,8 +1652,6 @@ void CSystem::CreateSystemVars() m_sys_memory_debug = REGISTER_INT("sys_memory_debug", 0, VF_CHEAT, "Enables to activate low memory situation is specific places in the code (argument defines which place), 0=off"); - REGISTER_CVAR2("sys_vtune", &g_cvars.sys_vtune, 0, VF_NULL, ""); - #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_17 #include AZ_RESTRICTED_FILE(SystemInit_cpp) From 600bb5b34ec8592a4c73817c04fb9bf2b947f890 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Thu, 4 Nov 2021 11:17:52 -0600 Subject: [PATCH 188/200] Fix alt-tabbing out of full screen on Windows. (#5288) Signed-off-by: bosnichd --- .../Windowing/NativeWindow_Windows.cpp | 23 +++++++++++++++++++ .../Windows/RHI/SwapChain_Windows.cpp | 3 --- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp index 57b37037ae..3bd0abab8d 100644 --- a/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp +++ b/Code/Framework/AzFramework/Platform/Windows/AzFramework/Windowing/NativeWindow_Windows.cpp @@ -54,6 +54,7 @@ namespace AzFramework RECT m_windowRectToRestoreOnFullScreenExit; //!< The position and size of the window to restore when exiting full screen. UINT m_windowStyleToRestoreOnFullScreenExit; //!< The style(s) of the window to restore when exiting full screen. bool m_isInBorderlessWindowFullScreenState = false; //!< Was a borderless window used to enter full screen state? + bool m_shouldEnterFullScreenStateOnActivate = false; //!< Should we enter full screen state when the window is activated? using GetDpiForWindowType = UINT(HWND hwnd); GetDpiForWindowType* m_getDpiFunction = nullptr; @@ -249,6 +250,28 @@ namespace AzFramework AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputCodeUnitUTF16Event, codeUnitUTF16); break; } + case WM_ACTIVATE: + { + // Alt-tabbing out of the app while it is in a full screen state does not + // work unless we explicitly exit the full screen state upon deactivation, + // in which case we want to enter full screen state again upon activation. + const bool windowIsNowInactive = (LOWORD(wParam) == WA_INACTIVE); + const bool windowFullScreenState = nativeWindowImpl->GetFullScreenState(); + if (windowIsNowInactive && + windowFullScreenState) + { + nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate = true; + nativeWindowImpl->SetFullScreenState(false); + } + else if (!windowIsNowInactive && + !windowFullScreenState && + nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate) + { + nativeWindowImpl->m_shouldEnterFullScreenStateOnActivate = false; + nativeWindowImpl->SetFullScreenState(true); + } + break; + } case WM_SYSKEYDOWN: { // Handle ALT+ENTER to toggle full screen unless exclsuive full screen diff --git a/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/SwapChain_Windows.cpp b/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/SwapChain_Windows.cpp index ab14f9b5d3..06477135f4 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/SwapChain_Windows.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/Platform/Windows/RHI/SwapChain_Windows.cpp @@ -82,9 +82,6 @@ namespace AZ // ALT+ENTER fullscreen switching using IDXGIFactory::MakeWindowAssociation (see also implementation of SwapChain::PresentInternal). // You must call the MakeWindowAssociation method after the creation of the swap chain, and on the factory object associated with the // target HWND swap chain, which you can guarantee by calling the IDXGIObject::GetParent method on the swap chain to locate the factory. - // - // ToDo: ATOM-14673 We should handle ALT+ENTER in the windows message loop and call AzFramework::NativeWindow::ToggleFullScreenState in - // response, but that will have to wait until the WndProc function moves out of CrySystem (ideally into AzFramework::ApplicationWindows). IDXGIFactoryX* parentFactory = nullptr; m_swapChain->GetParent(__uuidof(IDXGIFactoryX), (void **)&parentFactory); DX12::AssertSuccess(parentFactory->MakeWindowAssociation(reinterpret_cast(window), DXGI_MWA_NO_ALT_ENTER)); From 781a635ef72a9942852bc7a591d141ea715f8490 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:10:29 -0700 Subject: [PATCH 189/200] Cleanup: Remove cry load dll functions (#5295) * Removes VTUNE profiler hooks from Cry Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Remove cry load dll functions Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * removes unused restricted section Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- Code/Legacy/CryCommon/StlUtils.h | 337 --------------------------- Code/Legacy/CrySystem/System.cpp | 2 - Code/Legacy/CrySystem/System.h | 12 - Code/Legacy/CrySystem/SystemInit.cpp | 207 ---------------- 4 files changed, 558 deletions(-) diff --git a/Code/Legacy/CryCommon/StlUtils.h b/Code/Legacy/CryCommon/StlUtils.h index f5128a564f..ccbc854dc3 100644 --- a/Code/Legacy/CryCommon/StlUtils.h +++ b/Code/Legacy/CryCommon/StlUtils.h @@ -96,47 +96,6 @@ unsigned countElements (const std::vector& arrT, const T& x) */ namespace stl { - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Compare member of class/struct. - // - // e.g. Sort Vec3s by x component - // - // std::sort(vec3s.begin(), vec3s.end(), stl::member_compare()); - // - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - template > - struct member_compare - { - inline bool operator () (const OWNER_TYPE& lhs, const OWNER_TYPE& rhs) const - { - return EQUALITY()(lhs.*MEMBER_PTR, rhs.*MEMBER_PTR); - } - }; - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Compare member of class/struct against parameter. - // - // e.g. Find Vec3 with x component less than 1.0 - // - // std::find_if(vec3s.begin(), vec3s.end(), stl::member_compare_param(1.0f)); - // - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - template > - struct member_compare_param - { - inline member_compare_param(const MEMBER_TYPE& _value) - : value(_value) - { - } - - inline bool operator () (const OWNER_TYPE& rhs) const - { - return EQUALITY()(rhs.*MEMBER_PTR, value); - } - - const MEMBER_TYPE& value; - }; - ////////////////////////////////////////////////////////////////////////// //! Searches the given entry in the map by key, and if there is none, returns the default value ////////////////////////////////////////////////////////////////////////// @@ -154,48 +113,6 @@ namespace stl } } - ////////////////////////////////////////////////////////////////////////// - //! Inserts and returns a reference to the given value in the map, or returns the current one if it's already there. - ////////////////////////////////////////////////////////////////////////// - template - inline typename Map::mapped_type& map_insert_or_get(Map& mapKeyToValue, const typename Map::key_type& key, const typename Map::mapped_type& defValue = typename Map::mapped_type()) - { - auto&& iresult = mapKeyToValue.insert(typename Map::value_type(key, defValue)); - return iresult.first->second; - } - - // searches the given entry in the map by key, and if there is none, returns the default value - // The values are taken/returned in REFERENCEs rather than values - template - inline mapped_type& find_in_map_ref(std::map& mapKeyToValue, const Key& key, mapped_type& valueDefault) - { - typedef std::map Map; - typename Map::iterator it = mapKeyToValue.find (key); - if (it == mapKeyToValue.end()) - { - return valueDefault; - } - else - { - return it->second; - } - } - - template - inline const mapped_type& find_in_map_ref(const std::map& mapKeyToValue, const Key& key, const mapped_type& valueDefault) - { - typedef std::map Map; - typename Map::const_iterator it = mapKeyToValue.find (key); - if (it == mapKeyToValue.end()) - { - return valueDefault; - } - else - { - return it->second; - } - } - ////////////////////////////////////////////////////////////////////////// //! Fills vector with contents of map. ////////////////////////////////////////////////////////////////////////// @@ -210,20 +127,6 @@ namespace stl } } - ////////////////////////////////////////////////////////////////////////// - //! Fills vector with contents of set. - ////////////////////////////////////////////////////////////////////////// - template - inline void set_to_vector(const Set& theSet, Vector& array) - { - array.resize(0); - array.reserve(theSet.size()); - for (typename Set::const_iterator it = theSet.begin(); it != theSet.end(); ++it) - { - array.push_back(*it); - } - } - ////////////////////////////////////////////////////////////////////////// //! Find and erase element from container. // @return true if item was find and erased, false if item not found. @@ -312,48 +215,6 @@ namespace stl return false; } - ////////////////////////////////////////////////////////////////////////// - //! Push back to container unique element. - // @return true if item added, false overwise. - template - inline bool push_back_unique_if(CONTAINER& container, const PREDICATE& predicate, const VALUE& value) - { - typename CONTAINER::iterator end = container.end(); - - if (AZStd::find_if(container.begin(), end, predicate) == end) - { - container.push_back(value); - - return true; - } - else - { - return false; - } - } - - ////////////////////////////////////////////////////////////////////////// - //! Push back to container contents of another container - template - inline void push_back_range(Container& container, Iter begin, Iter end) - { - for (Iter it = begin; it != end; ++it) - { - container.push_back(*it); - } - } - - ////////////////////////////////////////////////////////////////////////// - //! Push back to container contents of another container, if not already present - template - inline void push_back_range_unique(Container& container, Iter begin, Iter end) - { - for (Iter it = begin; it != end; ++it) - { - push_back_unique(container, *it); - } - } - ////////////////////////////////////////////////////////////////////////// //! Find element in container. // @return true if item found. @@ -373,107 +234,6 @@ namespace stl return (it == last || value != *it) ? last : it; } - ////////////////////////////////////////////////////////////////////////// - //! Find element in a sorted container using binary search with logarithmic efficiency. - // @return true if item was inserted. - template - inline bool binary_insert_unique(Container& container, const Value& value) - { - typename Container::iterator it = std::lower_bound(container.begin(), container.end(), value); - if (it != container.end()) - { - if (*it == value) - { - return false; - } - container.insert(it, value); - } - else - { - container.insert(container.end(), value); - } - return true; - } - ////////////////////////////////////////////////////////////////////////// - //! Find element in a sorted container using binary search with logarithmic efficiency. - // and erases if element found. - // @return true if item was erased. - template - inline bool binary_erase(Container& container, const Value& value) - { - typename Container::iterator it = std::lower_bound(container.begin(), container.end(), value); - if (it != container.end() && *it == value) - { - container.erase(it); - return true; - } - return false; - } - - template - ItT remove_from_heap(ItT begin, ItT end, ItT at, Func order) - { - using std::swap; - - --end; - if (at == end) - { - return at; - } - - size_t idx = std::distance(begin, at); - swap(*end, *at); - - size_t length = std::distance(begin, end); - size_t parent, child; - - if (idx > 0 && order(*(begin + idx / 2), *(begin + idx))) - { - do - { - parent = idx / 2; - swap(*(begin + idx), *(begin + parent)); - idx = parent; - - if (idx == 0 || order(*(begin + idx), *(begin + idx / 2))) - { - return end; - } - } - while (true); - } - else - { - do - { - child = idx * 2 + 1; - if (child >= length) - { - return end; - } - - ItT left = begin + child; - ItT right = begin + child + 1; - - if (right < end && order(*left, *right)) - { - ++child; - } - - if (order(*(begin + child), *(begin + idx))) - { - return end; - } - - swap(*(begin + child), *(begin + idx)); - idx = child; - } - while (true); - } - - return end; - } - struct container_object_deleter { template @@ -506,18 +266,6 @@ namespace stl return type.c_str(); } - ////////////////////////////////////////////////////////////////////////// - //! Case sensetive less key for any type convertable to const char*. - ////////////////////////////////////////////////////////////////////////// - template - struct less_strcmp - { - bool operator()(const Type& left, const Type& right) const - { - return strcmp(constchar_cast(left), constchar_cast(right)) < 0; - } - }; - ////////////////////////////////////////////////////////////////////////// //! Case insensetive less key for any type convertable to const char*. template @@ -690,89 +438,4 @@ namespace stl stl::free_container(container); } }; - - template - inline void for_each_array(T (&buffer)[Length], Func func) - { - std::for_each(&buffer[0], &buffer[Length], func); - } - - template - inline void for_each_array(StaticInstance(&buffer)[Length], Func func) - { - for (size_t idx = 0; idx < Length; ++idx) - { - func(*buffer[idx]); - } - } - - template - inline void destruct(T* p) - { - p->~T(); - } -} - -#define DEFINE_INTRUSIVE_LINKED_LIST(Class) \ - template<> \ - Class * stl::intrusive_linked_list_node::m_root_intrusive = nullptr; - -// define the maplikestruct, used to approximate the memory requirements for a map node -namespace stl -{ - struct MapLikeStruct - { - bool color; - void* parent; - void* left; - void* right; - }; -} -template -unsigned sizeOfMap(Map& map) -{ - unsigned size = 0; - for (typename Map::iterator it = map.begin(); it != map.end(); it++) - { - typename Map::mapped_type& T = it->second; - size += T.Size(); - } - size += map.size() * sizeof(stl::MapLikeStruct); - return size; -} -template -unsigned sizeOfMapStr(Map& map) -{ - unsigned size = 0; - for (typename Map::iterator it = map.begin(); it != map.end(); it++) - { - typename Map::mapped_type& T = it->second; - size += T.capacity(); - } - size += map.size() * sizeof(stl::MapLikeStruct); - return size; -} -template -unsigned sizeOfMapP(Map& map) -{ - unsigned size = 0; - for (typename Map::iterator it = map.begin(); it != map.end(); it++) - { - typename Map::mapped_type& T = it->second; - size += T->Size(); - } - size += map.size() * sizeof(stl::MapLikeStruct); - return size; -} -template -unsigned sizeOfMapS(Map& map) -{ - unsigned size = 0; - for (typename Map::iterator it = map.begin(); it != map.end(); it++) - { - typename Map::mapped_type& T = it->second; - size += sizeof(T); - } - size += map.size() * sizeof(stl::MapLikeStruct); - return size; } diff --git a/Code/Legacy/CrySystem/System.cpp b/Code/Legacy/CrySystem/System.cpp index eebe626918..65facba4dd 100644 --- a/Code/Legacy/CrySystem/System.cpp +++ b/Code/Legacy/CrySystem/System.cpp @@ -509,8 +509,6 @@ void CSystem::ShutDown() ShutdownFileSystem(); - ShutdownModuleLibraries(); - EBUS_EVENT(CrySystemEventBus, OnCrySystemPostShutdown); } diff --git a/Code/Legacy/CrySystem/System.h b/Code/Legacy/CrySystem/System.h index 74ce1cbbc2..a10c1f8ed8 100644 --- a/Code/Legacy/CrySystem/System.h +++ b/Code/Legacy/CrySystem/System.h @@ -303,8 +303,6 @@ public: void SetVersionInfo(const char* const szVersion); #endif - void ShutdownModuleLibraries(); - #if defined(WIN32) friend LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); #endif @@ -323,8 +321,6 @@ private: // Release all resources. void ShutDown(); - bool LoadEngineDLLs(); - //! @name Initialization routines //@{ bool InitConsole(); @@ -340,11 +336,8 @@ private: void CreateSystemVars(); void CreateAudioVars(); - AZStd::unique_ptr LoadDLL(const char* dllName); - void FreeLib(AZStd::unique_ptr& hLibModule); - bool UnloadDLL(const char* dllName); void QueryVersionInfo(); void LogVersion(); void LogBuildInfo(); @@ -359,8 +352,6 @@ private: void AddCVarGroupDirectory(const AZStd::string& sPath) override; - AZStd::unique_ptr LoadDynamiclibrary(const char* dllName) const; - #if defined(AZ_RESTRICTED_PLATFORM) #define AZ_RESTRICTED_SECTION SYSTEM_H_SECTION_3 #include AZ_RESTRICTED_FILE(System_h) @@ -416,9 +407,6 @@ private: // ------------------------------------------------------ bool m_bDrawConsole; //!< Set to true if OK to draw the console. bool m_bDrawUI; //!< Set to true if OK to draw UI. - - std::map > m_moduleDLLHandles; - //! current active process IProcess* m_pProcess; diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp index 7ce9fcd342..d9ba3bb4c9 100644 --- a/Code/Legacy/CrySystem/SystemInit.cpp +++ b/Code/Legacy/CrySystem/SystemInit.cpp @@ -12,7 +12,6 @@ #if defined(AZ_RESTRICTED_PLATFORM) || defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) #undef AZ_RESTRICTED_SECTION -#define SYSTEMINIT_CPP_SECTION_1 1 #define SYSTEMINIT_CPP_SECTION_2 2 #define SYSTEMINIT_CPP_SECTION_3 3 #define SYSTEMINIT_CPP_SECTION_4 4 @@ -168,30 +167,6 @@ void CryEngineSignalHandler(int signal) #define LOCALIZATION_TRANSLATIONS_LIST_FILE_NAME "Libs/Localization/localization.xml" -////////////////////////////////////////////////////////////////////////// -#if defined(WIN32) || defined(LINUX) || defined(APPLE) -# define DLL_INITFUNC_RENDERER "PackageRenderConstructor" -# define DLL_INITFUNC_SOUND "CreateSoundSystem" -# define DLL_INITFUNC_FONT "CreateCryFontInterface" -# define DLL_INITFUNC_3DENGINE "CreateCry3DEngine" -# define DLL_INITFUNC_UI "CreateLyShineInterface" -#define AZ_RESTRICTED_SECTION_IMPLEMENTED -#elif defined(AZ_RESTRICTED_PLATFORM) -#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_1 -#include AZ_RESTRICTED_FILE(SystemInit_cpp) -#endif -#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED) -#undef AZ_RESTRICTED_SECTION_IMPLEMENTED -#else -# define DLL_INITFUNC_RENDERER (LPCSTR)1 -# define DLL_INITFUNC_RENDERER (LPCSTR)1 -# define DLL_INITFUNC_SOUND (LPCSTR)1 -# define DLL_INITFUNC_PHYSIC (LPCSTR)1 -# define DLL_INITFUNC_FONT (LPCSTR)1 -# define DLL_INITFUNC_3DENGINE (LPCSTR)1 -# define DLL_INITFUNC_UI (LPCSTR)1 -#endif - #define AZ_TRACE_SYSTEM_WINDOW AZ::Debug::Trace::GetDefaultSystemWindow() #ifdef WIN32 @@ -285,96 +260,6 @@ static void CmdCrashTest(IConsoleCmdArgs* pArgs) } AZ_POP_DISABLE_WARNING -////////////////////////////////////////////////////////////////////////// -struct SysSpecOverrideSink - : public ILoadConfigurationEntrySink -{ - virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup) - { - ICVar* pCvar = gEnv->pConsole->GetCVar(szKey); - - if (pCvar) - { - const bool wasNotInConfig = ((pCvar->GetFlags() & VF_WASINCONFIG) == 0); - bool applyCvar = wasNotInConfig; - if (applyCvar == false) - { - // Special handling for sys_spec_full - if (azstricmp(szKey, "sys_spec_full") == 0) - { - // If it is set to 0 then ignore this request to set to something else - // If it is set to 0 then the user wants to changes system spec settings in system.cfg - if (pCvar->GetIVal() != 0) - { - applyCvar = true; - } - } - else - { - // This could bypass the restricted cvar checks that exist elsewhere depending on - // the calling code so we also need check here before setting. - bool isConst = pCvar->IsConstCVar(); - bool isCheat = ((pCvar->GetFlags() & (VF_CHEAT | VF_CHEAT_NOCHECK | VF_CHEAT_ALWAYS_CHECK)) != 0); - bool isReadOnly = ((pCvar->GetFlags() & VF_READONLY) != 0); - bool isDeprecated = ((pCvar->GetFlags() & VF_DEPRECATED) != 0); - bool allowApplyCvar = true; - - if ((isConst || isCheat || isReadOnly) || isDeprecated) - { - allowApplyCvar = !isDeprecated && (gEnv->pSystem->IsDevMode()) || (gEnv->IsEditor()); - } - - if ((allowApplyCvar) || ALLOW_CONST_CVAR_MODIFICATIONS) - { - applyCvar = true; - } - } - } - - if (applyCvar) - { - pCvar->Set(szValue); - } - else - { - CryLogAlways("NOT VF_WASINCONFIG Ignoring cvar '%s' new value '%s' old value '%s' group '%s'", szKey, szValue, pCvar->GetString(), szGroup); - } - } - else - { - CryLogAlways("Can't find cvar '%s' value '%s' group '%s'", szKey, szValue, szGroup); - } - } -}; - -#if !defined(CONSOLE) -struct SysSpecOverrideSinkConsole - : public ILoadConfigurationEntrySink -{ - virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup) - { - // Ignore platform-specific cvars that should just be executed on the console - if (azstricmp(szGroup, "Platform") == 0) - { - return; - } - - ICVar* pCvar = gEnv->pConsole->GetCVar(szKey); - if (pCvar) - { - pCvar->Set(szValue); - } - else - { - // If the cvar doesn't exist, calling this function only saves the value in case it's registered later where - // at that point it will be set from the stored value. This is required because otherwise registering the - // cvar bypasses any callbacks and uses values directly from the cvar group files. - gEnv->pConsole->LoadConfigVar(szKey, szValue); - } - } -}; -#endif - static ESystemConfigPlatform GetDevicePlatform() { #if defined(AZ_PLATFORM_WINDOWS) || defined(AZ_PLATFORM_LINUX) @@ -398,98 +283,6 @@ static ESystemConfigPlatform GetDevicePlatform() #endif } -////////////////////////////////////////////////////////////////////////// -#if !defined(AZ_MONOLITHIC_BUILD) - -AZStd::unique_ptr CSystem::LoadDynamiclibrary(const char* dllName) const -{ - AZStd::unique_ptr handle = AZ::DynamicModuleHandle::Create(dllName); - - bool libraryLoaded = handle->Load(false); - // We need to inject the environment first thing so that allocators are available immediately - InjectEnvironmentFunction injectEnv = handle->GetFunction(INJECT_ENVIRONMENT_FUNCTION); - if (injectEnv) - { - auto env = AZ::Environment::GetInstance(); - injectEnv(env); - } - - if (!libraryLoaded) - { - handle.release(); - } - return handle; -} - -////////////////////////////////////////////////////////////////////////// -AZStd::unique_ptr CSystem::LoadDLL(const char* dllName) -{ - AZ_TracePrintf(AZ_TRACE_SYSTEM_WINDOW, "Loading DLL: %s", dllName); - - AZStd::unique_ptr handle = LoadDynamiclibrary(dllName); - - if (!handle) - { -#if defined(LINUX) || defined(APPLE) - AZ_Assert(false, "Error loading dylib: %s, error : %s\n", dllName, dlerror()); -#else - AZ_Assert(false, "Error loading dll: %s, error code %d", dllName, GetLastError()); -#endif - return handle; - } - - return handle; -} - -// TODO:DLL #endif //#if defined(AZ_HAS_DLL_SUPPORT) && !defined(AZ_MONOLITHIC_BUILD) -#endif //if !defined(AZ_MONOLITHIC_BUILD) -////////////////////////////////////////////////////////////////////////// -bool CSystem::LoadEngineDLLs() -{ - return true; -} - -////////////////////////////////////////////////////////////////////////// -bool CSystem::UnloadDLL(const char* dllName) -{ - bool isSuccess = false; - - AZ::Crc32 key(dllName); - AZStd::unique_ptr empty; - AZStd::unique_ptr& hModule = stl::find_in_map_ref(m_moduleDLLHandles, key, empty); - if ((hModule) && (hModule->IsLoaded())) - { - DetachEnvironmentFunction detachEnv = hModule->GetFunction(DETACH_ENVIRONMENT_FUNCTION); - if (detachEnv) - { - detachEnv(); - } - - isSuccess = hModule->Unload(); - hModule.release(); - } - - return isSuccess; -} - -////////////////////////////////////////////////////////////////////////// -void CSystem::ShutdownModuleLibraries() -{ -#if !defined(AZ_MONOLITHIC_BUILD) - for (auto iterator = m_moduleDLLHandles.begin(); iterator != m_moduleDLLHandles.end(); ++iterator) - { - if (iterator->second->IsLoaded()) - { - iterator->second->Unload(); - } - iterator->second.release(); - } - - m_moduleDLLHandles.clear(); - -#endif // !defined(AZ_MONOLITHIC_BUILD) -} - ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// bool CSystem::InitConsole() From bc2b3b12a70d3ef3977e739ca407b6b3f5a8e8c3 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:51:58 -0700 Subject: [PATCH 190/200] remove old main suite, rename optimized main suite to be the new main suite Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 322 +++++------------- .../Atom/TestSuite_Main_Optimized.py | 91 ----- 2 files changed, 79 insertions(+), 334 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index 6cc48984ab..950bd44199 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -4,252 +4,88 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import logging -import os - import pytest -import ly_test_tools.environment.file_system as file_system -import editor_python_test_tools.hydra_test_utils as hydra -from Atom.atom_utils.atom_constants import LIGHT_TYPES - -logger = logging.getLogger(__name__) -TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") +from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite +@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("level", ["auto_test"]) -class TestAtomEditorComponentsMain(object): - """Holds tests for Atom components.""" - - @pytest.mark.test_case_id("C32078118") # Decal - @pytest.mark.test_case_id("C32078119") # DepthOfField - @pytest.mark.test_case_id("C32078120") # Directional Light - @pytest.mark.test_case_id("C32078121") # Exposure Control - @pytest.mark.test_case_id("C32078115") # Global Skylight (IBL) - @pytest.mark.test_case_id("C32078125") # Physical Sky - @pytest.mark.test_case_id("C32078127") # PostFX Layer - @pytest.mark.test_case_id("C32078131") # PostFX Radius Weight Modifier - @pytest.mark.test_case_id("C32078117") # Light - @pytest.mark.test_case_id("C36525660") # Display Mapper - def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform): - """ - Please review the hydra script run by this test for more specific test info. - Tests the Atom components & verifies all "expected_lines" appear in Editor.log - """ - cfg_args = [level] - - expected_lines = [ - # Decal Component - "Decal Entity successfully created", - "Decal_test: Component added to the entity: True", - "Decal_test: Component removed after UNDO: True", - "Decal_test: Component added after REDO: True", - "Decal_test: Entered game mode: True", - "Decal_test: Exit game mode: True", - "Decal Controller|Configuration|Material: SUCCESS", - "Decal_test: Entity is hidden: True", - "Decal_test: Entity is shown: True", - "Decal_test: Entity deleted: True", - "Decal_test: UNDO entity deletion works: True", - "Decal_test: REDO entity deletion works: True", - # DepthOfField Component - "DepthOfField Entity successfully created", - "DepthOfField_test: Component added to the entity: True", - "DepthOfField_test: Component removed after UNDO: True", - "DepthOfField_test: Component added after REDO: True", - "DepthOfField_test: Entered game mode: True", - "DepthOfField_test: Exit game mode: True", - "DepthOfField_test: Entity disabled initially: True", - "DepthOfField_test: Entity enabled after adding required components: True", - "DepthOfField Controller|Configuration|Camera Entity: SUCCESS", - "DepthOfField_test: Entity is hidden: True", - "DepthOfField_test: Entity is shown: True", - "DepthOfField_test: Entity deleted: True", - "DepthOfField_test: UNDO entity deletion works: True", - "DepthOfField_test: REDO entity deletion works: True", - # Directional Light Component - "Directional Light Entity successfully created", - "Directional Light_test: Component added to the entity: True", - "Directional Light_test: Component removed after UNDO: True", - "Directional Light_test: Component added after REDO: True", - "Directional Light_test: Entered game mode: True", - "Directional Light_test: Exit game mode: True", - "Directional Light_test: Entity is hidden: True", - "Directional Light_test: Entity is shown: True", - "Directional Light_test: Entity deleted: True", - "Directional Light_test: UNDO entity deletion works: True", - "Directional Light_test: REDO entity deletion works: True", - # Exposure Control Component - "Exposure Control Entity successfully created", - "Exposure Control_test: Component added to the entity: True", - "Exposure Control_test: Component removed after UNDO: True", - "Exposure Control_test: Component added after REDO: True", - "Exposure Control_test: Entered game mode: True", - "Exposure Control_test: Exit game mode: True", - "Exposure Control_test: Entity disabled initially: True", - "Exposure Control_test: Entity enabled after adding required components: True", - "Exposure Control_test: Entity is hidden: True", - "Exposure Control_test: Entity is shown: True", - "Exposure Control_test: Entity deleted: True", - "Exposure Control_test: UNDO entity deletion works: True", - "Exposure Control_test: REDO entity deletion works: True", - # Global Skylight (IBL) Component - "Global Skylight (IBL) Entity successfully created", - "Global Skylight (IBL)_test: Component added to the entity: True", - "Global Skylight (IBL)_test: Component removed after UNDO: True", - "Global Skylight (IBL)_test: Component added after REDO: True", - "Global Skylight (IBL)_test: Entered game mode: True", - "Global Skylight (IBL)_test: Exit game mode: True", - "Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS", - "Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS", - "Global Skylight (IBL)_test: Entity is hidden: True", - "Global Skylight (IBL)_test: Entity is shown: True", - "Global Skylight (IBL)_test: Entity deleted: True", - "Global Skylight (IBL)_test: UNDO entity deletion works: True", - "Global Skylight (IBL)_test: REDO entity deletion works: True", - # Physical Sky Component - "Physical Sky Entity successfully created", - "Physical Sky component was added to entity", - "Entity has a Physical Sky component", - "Physical Sky_test: Component added to the entity: True", - "Physical Sky_test: Component removed after UNDO: True", - "Physical Sky_test: Component added after REDO: True", - "Physical Sky_test: Entered game mode: True", - "Physical Sky_test: Exit game mode: True", - "Physical Sky_test: Entity is hidden: True", - "Physical Sky_test: Entity is shown: True", - "Physical Sky_test: Entity deleted: True", - "Physical Sky_test: UNDO entity deletion works: True", - "Physical Sky_test: REDO entity deletion works: True", - # PostFX Layer Component - "PostFX Layer Entity successfully created", - "PostFX Layer_test: Component added to the entity: True", - "PostFX Layer_test: Component removed after UNDO: True", - "PostFX Layer_test: Component added after REDO: True", - "PostFX Layer_test: Entered game mode: True", - "PostFX Layer_test: Exit game mode: True", - "PostFX Layer_test: Entity is hidden: True", - "PostFX Layer_test: Entity is shown: True", - "PostFX Layer_test: Entity deleted: True", - "PostFX Layer_test: UNDO entity deletion works: True", - "PostFX Layer_test: REDO entity deletion works: True", - # PostFX Radius Weight Modifier Component - "PostFX Radius Weight Modifier Entity successfully created", - "PostFX Radius Weight Modifier_test: Component added to the entity: True", - "PostFX Radius Weight Modifier_test: Component removed after UNDO: True", - "PostFX Radius Weight Modifier_test: Component added after REDO: True", - "PostFX Radius Weight Modifier_test: Entered game mode: True", - "PostFX Radius Weight Modifier_test: Exit game mode: True", - "PostFX Radius Weight Modifier_test: Entity is hidden: True", - "PostFX Radius Weight Modifier_test: Entity is shown: True", - "PostFX Radius Weight Modifier_test: Entity deleted: True", - "PostFX Radius Weight Modifier_test: UNDO entity deletion works: True", - "PostFX Radius Weight Modifier_test: REDO entity deletion works: True", - # Light Component - "Light Entity successfully created", - "Light_test: Component added to the entity: True", - "Light_test: Component removed after UNDO: True", - "Light_test: Component added after REDO: True", - "Light_test: Entered game mode: True", - "Light_test: Exit game mode: True", - "Light_test: Entity is hidden: True", - "Light_test: Entity is shown: True", - "Light_test: Entity deleted: True", - "Light_test: UNDO entity deletion works: True", - "Light_test: REDO entity deletion works: True", - # Display Mapper Component - "Display Mapper Entity successfully created", - "Display Mapper_test: Component added to the entity: True", - "Display Mapper_test: Component removed after UNDO: True", - "Display Mapper_test: Component added after REDO: True", - "Display Mapper_test: Entered game mode: True", - "Display Mapper_test: Exit game mode: True", - "Display Mapper_test: Entity is hidden: True", - "Display Mapper_test: Entity is shown: True", - "Display Mapper_test: Entity deleted: True", - "Display Mapper_test: UNDO entity deletion works: True", - "Display Mapper_test: REDO entity deletion works: True", - ] - - unexpected_lines = [ - "Trace::Assert", - "Trace::Error", - "Traceback (most recent call last):", - ] - - hydra.launch_and_validate_results( - request, - TEST_DIRECTORY, - editor, - "hydra_AtomEditorComponents_AddedToEntity.py", - timeout=120, - expected_lines=expected_lines, - unexpected_lines=unexpected_lines, - halt_on_unexpected=True, - null_renderer=True, - cfg_args=cfg_args, - ) - - @pytest.mark.test_case_id("C34525095") - def test_AtomEditorComponents_LightComponent( - self, request, editor, workspace, project, launcher_platform, level): - """ - Please review the hydra script run by this test for more specific test info. - Tests that the Light component has the expected property options available to it. - """ - cfg_args = [level] - - expected_lines = [ - "light_entity Entity successfully created", - "Entity has a Light component", - "light_entity_test: Component added to the entity: True", - f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}", - "Controller|Configuration|Shadows|Enable shadow set to True", - "light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS", - "Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF - "Controller|Configuration|Shadows|Filtering sample count set to 4", - "Controller|Configuration|Shadows|Filtering sample count set to 64", - "Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM - "Controller|Configuration|Shadows|ESM exponent set to 50.0", - "Controller|Configuration|Shadows|ESM exponent set to 5000.0", - "Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF - f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}", - f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}", - f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}", - "light_entity Controller|Configuration|Fast approximation: SUCCESS", - "light_entity Controller|Configuration|Both directions: SUCCESS", - f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}", - f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} " - f"which matches {LIGHT_TYPES['simple_point']}", - "Controller|Configuration|Attenuation radius|Mode set to 0", - "Controller|Configuration|Attenuation radius|Radius set to 100.0", - f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} " - f"which matches {LIGHT_TYPES['simple_spot']}", - "Controller|Configuration|Shutters|Outer angle set to 45.0", - "Controller|Configuration|Shutters|Outer angle set to 90.0", - "light_entity_test: Component added to the entity: True", - "Light component test (non-GPU) completed.", - ] - - unexpected_lines = [ - "Trace::Assert", - "Trace::Error", - "Traceback (most recent call last):", - ] - - hydra.launch_and_validate_results( - request, - TEST_DIRECTORY, - editor, - "hydra_AtomEditorComponents_LightComponent.py", - timeout=120, - expected_lines=expected_lines, - unexpected_lines=unexpected_lines, - halt_on_unexpected=True, - null_renderer=True, - cfg_args=cfg_args, - ) - - +class TestAutomation(EditorTestSuite): + + @pytest.mark.test_case_id("C32078118") + class AtomEditorComponents_DecalAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module + + @pytest.mark.test_case_id("C32078119") + class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module + + @pytest.mark.test_case_id("C32078120") + class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module + + @pytest.mark.test_case_id("C36525660") + class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module + + @pytest.mark.test_case_id("C32078121") + class AtomEditorComponents_ExposureControlAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module + + @pytest.mark.test_case_id("C32078115") + class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module + + @pytest.mark.test_case_id("C32078122") + class AtomEditorComponents_GridAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module + + @pytest.mark.test_case_id("C36525671") + class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module + + @pytest.mark.test_case_id("C32078117") + class AtomEditorComponents_LightAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module + + @pytest.mark.test_case_id("C32078123") + class AtomEditorComponents_MaterialAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module + + @pytest.mark.test_case_id("C32078124") + class AtomEditorComponents_MeshAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module + + @pytest.mark.test_case_id("C36525663") + class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module + + @pytest.mark.test_case_id("C32078125") + class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module + + @pytest.mark.test_case_id("C36525664") + class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module + + @pytest.mark.test_case_id("C32078127") + class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module + + @pytest.mark.test_case_id("C32078131") + class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest): + from Atom.tests import ( + hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module) + + @pytest.mark.test_case_id("C36525665") + class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module + + @pytest.mark.test_case_id("C32078128") + class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module + + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): + from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py deleted file mode 100644 index 950bd44199..0000000000 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" -import pytest - -from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite - - -@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -class TestAutomation(EditorTestSuite): - - @pytest.mark.test_case_id("C32078118") - class AtomEditorComponents_DecalAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module - - @pytest.mark.test_case_id("C32078119") - class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module - - @pytest.mark.test_case_id("C32078120") - class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module - - @pytest.mark.test_case_id("C36525660") - class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module - - @pytest.mark.test_case_id("C32078121") - class AtomEditorComponents_ExposureControlAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module - - @pytest.mark.test_case_id("C32078115") - class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module - - @pytest.mark.test_case_id("C32078122") - class AtomEditorComponents_GridAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_GridAdded as test_module - - @pytest.mark.test_case_id("C36525671") - class AtomEditorComponents_HDRColorGradingAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_HDRColorGradingAdded as test_module - - @pytest.mark.test_case_id("C32078117") - class AtomEditorComponents_LightAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module - - @pytest.mark.test_case_id("C32078123") - class AtomEditorComponents_MaterialAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_MaterialAdded as test_module - - @pytest.mark.test_case_id("C32078124") - class AtomEditorComponents_MeshAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module - - @pytest.mark.test_case_id("C36525663") - class AtomEditorComponents_OcclusionCullingPlaneAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_OcclusionCullingPlaneAdded as test_module - - @pytest.mark.test_case_id("C32078125") - class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module - - @pytest.mark.test_case_id("C36525664") - class AtomEditorComponents_PostFXGradientWeightModifierAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded as test_module - - @pytest.mark.test_case_id("C32078127") - class AtomEditorComponents_PostFXLayerAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_PostFXLayerAdded as test_module - - @pytest.mark.test_case_id("C32078131") - class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest): - from Atom.tests import ( - hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module) - - @pytest.mark.test_case_id("C36525665") - class AtomEditorComponents_PostFXShapeWeightModifierAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded as test_module - - @pytest.mark.test_case_id("C32078128") - class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module - - class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): - from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module From 16526f58b7f0a4c02a90d3c8ca2ddec84bdc47f7 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:52:28 -0700 Subject: [PATCH 191/200] remove xfail marker Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index 950bd44199..62a402d9c4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -9,7 +9,6 @@ import pytest from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite -@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.") @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): From b82ea09a67bec33a19e657d60b834da8e4dcb25c Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:54:21 -0700 Subject: [PATCH 192/200] remove redundant sandbox test, remove unsued/old hydra script for old log lines test approach Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- ...ydra_AtomEditorComponents_AddedToEntity.py | 238 ------------------ 1 file changed, 238 deletions(-) delete mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py deleted file mode 100644 index bbc8463152..0000000000 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py +++ /dev/null @@ -1,238 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import sys - -import azlmbr.math as math -import azlmbr.bus as bus -import azlmbr.paths -import azlmbr.asset as asset -import azlmbr.entity as entity -import azlmbr.legacy.general as general -import azlmbr.editor as editor -import azlmbr.render as render - -sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests")) - -import editor_python_test_tools.hydra_editor_utils as hydra -from editor_python_test_tools.utils import TestHelper - - -def run(): - """ - Summary: - The below common tests are done for each of the components. - 1) Addition of component to the entity - 2) UNDO/REDO of addition of component - 3) Enter/Exit game mode - 4) Hide/Show entity containing component - 5) Deletion of component - 6) UNDO/REDO of deletion of component - Some additional tests for specific components include - 1) Assigning value to some properties of each component - 2) Verifying if the component is activated only when the required components are added - - Expected Result: - 1) Component can be added to an entity. - 2) The addition of component can be undone and redone. - 3) Game mode can be entered/exited without issue. - 4) Entity with component can be hidden/shown. - 5) Component can be deleted. - 6) The deletion of component can be undone and redone. - 7) Component is activated only when the required components are added - 8) Values can be assigned to the properties of the component - - :return: None - """ - - def create_entity_undo_redo_component_addition(component_name): - new_entity = hydra.Entity(f"{component_name}") - new_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), [component_name]) - general.log(f"{component_name}_test: Component added to the entity: " - f"{hydra.has_components(new_entity.id, [component_name])}") - - # undo component addition - general.undo() - TestHelper.wait_for_condition(lambda: not hydra.has_components(new_entity.id, [component_name]), 2.0) - general.log(f"{component_name}_test: Component removed after UNDO: " - f"{not hydra.has_components(new_entity.id, [component_name])}") - - # redo component addition - general.redo() - TestHelper.wait_for_condition(lambda: hydra.has_components(new_entity.id, [component_name]), 2.0) - general.log(f"{component_name}_test: Component added after REDO: " - f"{hydra.has_components(new_entity.id, [component_name])}") - - return new_entity - - def verify_enter_exit_game_mode(component_name): - general.enter_game_mode() - TestHelper.wait_for_condition(lambda: general.is_in_game_mode(), 2.0) - general.log(f"{component_name}_test: Entered game mode: {general.is_in_game_mode()}") - general.exit_game_mode() - TestHelper.wait_for_condition(lambda: not general.is_in_game_mode(), 2.0) - general.log(f"{component_name}_test: Exit game mode: {not general.is_in_game_mode()}") - - def verify_hide_unhide_entity(component_name, entity_obj): - - def is_entity_hidden(entity_id): - return editor.EditorEntityInfoRequestBus(bus.Event, "IsHidden", entity_id) - - editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, False) - general.idle_wait_frames(1) - general.log(f"{component_name}_test: Entity is hidden: {is_entity_hidden(entity_obj.id)}") - editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", entity_obj.id, True) - general.idle_wait_frames(1) - general.log(f"{component_name}_test: Entity is shown: {not is_entity_hidden(entity_obj.id)}") - - def verify_deletion_undo_redo(component_name, entity_obj): - editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntityById", entity_obj.id) - TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0) - general.log(f"{component_name}_test: Entity deleted: {not hydra.find_entity_by_name(entity_obj.name)}") - - general.undo() - TestHelper.wait_for_condition(lambda: hydra.find_entity_by_name(entity_obj.name) is not None, 2.0) - general.log(f"{component_name}_test: UNDO entity deletion works: " - f"{hydra.find_entity_by_name(entity_obj.name) is not None}") - - general.redo() - TestHelper.wait_for_condition(lambda: not hydra.find_entity_by_name(entity_obj.name), 2.0) - general.log(f"{component_name}_test: REDO entity deletion works: " - f"{not hydra.find_entity_by_name(entity_obj.name)}") - - def verify_required_component_addition(entity_obj, components_to_add, component_name): - - def is_component_enabled(entity_componentid_pair): - return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", entity_componentid_pair) - - general.log( - f"{component_name}_test: Entity disabled initially: " - f"{not is_component_enabled(entity_obj.components[0])}") - for component in components_to_add: - entity_obj.add_component(component) - TestHelper.wait_for_condition(lambda: is_component_enabled(entity_obj.components[0]), 2.0) - general.log( - f"{component_name}_test: Entity enabled after adding " - f"required components: {is_component_enabled(entity_obj.components[0])}" - ) - - def verify_set_property(entity_obj, path, value): - entity_obj.get_set_test(0, path, value) - - # Verify cubemap generation - def verify_cubemap_generation(component_name, entity_obj): - # Initially Check if the component has Reflection Probe component - if not hydra.has_components(entity_obj.id, ["Reflection Probe"]): - raise ValueError(f"Given entity {entity_obj.name} has no Reflection Probe component") - render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", entity_obj.id) - - def get_value(): - hydra.get_component_property_value(entity_obj.components[0], "Cubemap|Baked Cubemap Path") - - TestHelper.wait_for_condition(lambda: get_value() != "", 20.0) - general.log(f"{component_name}_test: Cubemap is generated: {get_value() != ''}") - - # Wait for Editor idle loop before executing Python hydra scripts. - TestHelper.init_idle() - - # Delete all existing entities initially - search_filter = azlmbr.entity.SearchFilter() - all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter) - editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities) - - class ComponentTests: - """Test launcher for each component.""" - def __init__(self, component_name, *additional_tests): - self.component_name = component_name - self.additional_tests = additional_tests - self.run_component_tests() - - def run_component_tests(self): - # Run common and additional tests - entity_obj = create_entity_undo_redo_component_addition(self.component_name) - - # Enter/Exit game mode test - verify_enter_exit_game_mode(self.component_name) - - # Any additional tests are executed here - for test in self.additional_tests: - test(entity_obj) - - # Hide/Unhide entity test - verify_hide_unhide_entity(self.component_name, entity_obj) - - # Deletion/Undo/Redo test - verify_deletion_undo_redo(self.component_name, entity_obj) - - # DepthOfField Component - camera_entity = hydra.Entity("camera_entity") - camera_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), ["Camera"]) - depth_of_field = "DepthOfField" - ComponentTests( - depth_of_field, - lambda entity_obj: verify_required_component_addition(entity_obj, ["PostFX Layer"], depth_of_field), - lambda entity_obj: verify_set_property( - entity_obj, "Controller|Configuration|Camera Entity", camera_entity.id)) - - # Decal Component - material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material") - material_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False) - ComponentTests( - "Decal", lambda entity_obj: verify_set_property( - entity_obj, "Controller|Configuration|Material", material_asset)) - - # Directional Light Component - ComponentTests( - "Directional Light", - lambda entity_obj: verify_set_property( - entity_obj, "Controller|Configuration|Shadow|Camera", camera_entity.id)) - - # Exposure Control Component - ComponentTests( - "Exposure Control", lambda entity_obj: verify_required_component_addition( - entity_obj, ["PostFX Layer"], "Exposure Control")) - - # Global Skylight (IBL) Component - diffuse_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage") - diffuse_image_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", diffuse_image_path, math.Uuid(), False) - specular_image_path = os.path.join("LightingPresets", "greenwich_park_02_4k_iblskyboxcm.exr.streamingimage") - specular_image_asset = asset.AssetCatalogRequestBus( - bus.Broadcast, "GetAssetIdByPath", specular_image_path, math.Uuid(), False) - ComponentTests( - "Global Skylight (IBL)", - lambda entity_obj: verify_set_property( - entity_obj, "Controller|Configuration|Diffuse Image", diffuse_image_asset), - lambda entity_obj: verify_set_property( - entity_obj, "Controller|Configuration|Specular Image", specular_image_asset)) - - # Physical Sky Component - ComponentTests("Physical Sky") - - # PostFX Layer Component - ComponentTests("PostFX Layer") - - # PostFX Radius Weight Modifier Component - ComponentTests("PostFX Radius Weight Modifier") - - # Light Component - ComponentTests("Light") - - # Display Mapper Component - ComponentTests("Display Mapper") - - # Reflection Probe Component - reflection_probe = "Reflection Probe" - ComponentTests( - reflection_probe, - lambda entity_obj: verify_required_component_addition(entity_obj, ["Box Shape"], reflection_probe), - lambda entity_obj: verify_cubemap_generation(reflection_probe, entity_obj),) - -if __name__ == "__main__": - run() From ae72463581d7bcf59ee3f8f9816ab81c3a89b3e6 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:54:49 -0700 Subject: [PATCH 193/200] sandbox portion Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 50 +------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index ad45e51080..55b1540b7e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -9,63 +9,19 @@ import os import pytest +import ly_test_tools.environment.file_system as file_system import editor_python_test_tools.hydra_test_utils as hydra logger = logging.getLogger(__name__) TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") + class TestAtomEditorComponentsSandbox(object): # It requires at least one test def test_Dummy(self, request, editor, level, workspace, project, launcher_platform): pass - @pytest.mark.parametrize("project", ["AutomatedTesting"]) - @pytest.mark.parametrize("launcher_platform", ['windows_editor']) - @pytest.mark.parametrize("level", ["auto_test"]) - class TestAtomEditorComponentsMain(object): - """Holds tests for Atom components.""" - - @pytest.mark.test_case_id("C32078128") - def test_AtomEditorComponents_ReflectionProbeAddedToEntity( - self, request, editor, level, workspace, project, launcher_platform): - """ - Please review the hydra script run by this test for more specific test info. - Tests the following Atom components and verifies all "expected_lines" appear in Editor.log: - 1. Reflection Probe - """ - cfg_args = [level] - - expected_lines = [ - # Reflection Probe Component - "Reflection Probe Entity successfully created", - "Reflection Probe_test: Component added to the entity: True", - "Reflection Probe_test: Component removed after UNDO: True", - "Reflection Probe_test: Component added after REDO: True", - "Reflection Probe_test: Entered game mode: True", - "Reflection Probe_test: Exit game mode: True", - "Reflection Probe_test: Entity disabled initially: True", - "Reflection Probe_test: Entity enabled after adding required components: True", - "Reflection Probe_test: Cubemap is generated: True", - "Reflection Probe_test: Entity is hidden: True", - "Reflection Probe_test: Entity is shown: True", - "Reflection Probe_test: Entity deleted: True", - "Reflection Probe_test: UNDO entity deletion works: True", - "Reflection Probe_test: REDO entity deletion works: True", - ] - - hydra.launch_and_validate_results( - request, - TEST_DIRECTORY, - editor, - "hydra_AtomEditorComponents_AddedToEntity.py", - timeout=120, - expected_lines=expected_lines, - unexpected_lines=[], - halt_on_unexpected=True, - null_renderer=True, - cfg_args=cfg_args, - ) @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_generic']) @@ -119,8 +75,6 @@ class TestMaterialEditorBasicTests(object): "Save All worked as expected: True", ] unexpected_lines = [ - # "Trace::Assert", - # "Trace::Error", "Traceback (most recent call last):" ] From 6f294457da88290ef3a542dfb5c1b8ac943bc82f Mon Sep 17 00:00:00 2001 From: Vishal Das Date: Fri, 5 Nov 2021 00:41:31 +0530 Subject: [PATCH 194/200] fix issue #5172 (#5198) Signed-off-by: Vishal Das --- .../ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss | 1 - .../AzToolsFramework/UI/Outliner/EntityOutliner.qss | 1 - 2 files changed, 2 deletions(-) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss index de35f91678..a7d3949527 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/EntityOutliner.qss @@ -11,7 +11,6 @@ OutlinerWidget #m_display_options { qproperty-icon: url(:/Menu/menu.svg); qproperty-iconSize: 16px 16px; - qproperty-flat: true; } OutlinerWidget QWidget[PulseHighlight="true"] diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss index b3c5882334..93460f8816 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss @@ -10,7 +10,6 @@ AzToolsFramework--EntityOutlinerWidget #m_display_options { qproperty-icon: url(:/stylesheet/img/UI20/menu-centered.svg); qproperty-iconSize: 16px 16px; - qproperty-flat: true; } AzToolsFramework--EntityOutlinerWidget QTreeView From f26e272a8dc39e1e94946f4e8e32367f48963072 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:20:38 -0700 Subject: [PATCH 195/200] move light component non optimized test to sandbox until it gets optimized (ticket cut for this) Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index 55b1540b7e..9ceb3c951f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -12,6 +12,8 @@ import pytest import ly_test_tools.environment.file_system as file_system import editor_python_test_tools.hydra_test_utils as hydra +from Atom.atom_utils.atom_constants import LIGHT_TYPES + logger = logging.getLogger(__name__) TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") @@ -23,6 +25,69 @@ class TestAtomEditorComponentsSandbox(object): pass +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("level", ["auto_test"]) +class TestAtomEditorComponentsMain(object): + """Holds tests for Atom components.""" + + @pytest.mark.test_case_id("C34525095") + def test_AtomEditorComponents_LightComponent( + self, request, editor, workspace, project, launcher_platform, level): + """ + Please review the hydra script run by this test for more specific test info. + Tests that the Light component has the expected property options available to it. + """ + cfg_args = [level] + + expected_lines = [ + "light_entity Entity successfully created", + "Entity has a Light component", + "light_entity_test: Component added to the entity: True", + f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}", + "Controller|Configuration|Shadows|Enable shadow set to True", + "light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS", + "Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF + "Controller|Configuration|Shadows|Filtering sample count set to 4", + "Controller|Configuration|Shadows|Filtering sample count set to 64", + "Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM + "Controller|Configuration|Shadows|ESM exponent set to 50.0", + "Controller|Configuration|Shadows|ESM exponent set to 5000.0", + "Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF + f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}", + f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}", + f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}", + "light_entity Controller|Configuration|Fast approximation: SUCCESS", + "light_entity Controller|Configuration|Both directions: SUCCESS", + f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}", + f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} " + f"which matches {LIGHT_TYPES['simple_point']}", + "Controller|Configuration|Attenuation radius|Mode set to 0", + "Controller|Configuration|Attenuation radius|Radius set to 100.0", + f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} " + f"which matches {LIGHT_TYPES['simple_spot']}", + "Controller|Configuration|Shutters|Outer angle set to 45.0", + "Controller|Configuration|Shutters|Outer angle set to 90.0", + "light_entity_test: Component added to the entity: True", + "Light component test (non-GPU) completed.", + ] + + unexpected_lines = ["Traceback (most recent call last):"] + + hydra.launch_and_validate_results( + request, + TEST_DIRECTORY, + editor, + "hydra_AtomEditorComponents_LightComponent.py", + timeout=120, + expected_lines=expected_lines, + unexpected_lines=unexpected_lines, + halt_on_unexpected=True, + null_renderer=True, + cfg_args=cfg_args, + ) + + @pytest.mark.parametrize("project", ["AutomatedTesting"]) @pytest.mark.parametrize("launcher_platform", ['windows_generic']) @pytest.mark.system From 5a3cd96eab655260f494daca914e91e8bc492725 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Thu, 4 Nov 2021 12:23:41 -0700 Subject: [PATCH 196/200] Fixes for CMake 3.22rc (#5314) Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- .../Platform/Common/MSVC/Configurations_msvc.cmake | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake index a4d8533626..66a5b7b01f 100644 --- a/cmake/Platform/Common/MSVC/Configurations_msvc.cmake +++ b/cmake/Platform/Common/MSVC/Configurations_msvc.cmake @@ -139,11 +139,20 @@ endif() # Configure system includes ly_set(LY_CXX_SYSTEM_INCLUDE_CONFIGURATION_FLAG - /experimental:external # Turns on "external" headers feature for MSVC compilers + /experimental:external # Turns on "external" headers feature for MSVC compilers, required for MSVC < 16.10 /external:W0 # Set warning level in external headers to 0. This is used to suppress warnings 3rdParty libraries which uses the "system_includes" option in their json configuration ) + +# CMake 3.22rc added a definition for CMAKE_INCLUDE_SYSTEM_FLAG_CXX. However, its defined as "-external:I ", that space causes +# issues when trying to use in TargetIncludeSystemDirectories_unsupported.cmake. +# CMake 3.22rc has also not added support for external directories in MSVC through target_include_directories(... SYSTEM +# So we will just fix the flag that was added by 3.22rc so it works with our TargetIncludeSystemDirectories_unsupported.cmake +# Once target_include_directories(... SYSTEM is supported, we can branch and use TargetIncludeSystemDirectories_supported.cmake +# Reported this here: https://gitlab.kitware.com/cmake/cmake/-/issues/17904#note_1078281 if(NOT CMAKE_INCLUDE_SYSTEM_FLAG_CXX) - ly_set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX /external:I) + ly_set(CMAKE_INCLUDE_SYSTEM_FLAG_CXX "/external:I") +else() + string(STRIP ${CMAKE_INCLUDE_SYSTEM_FLAG_CXX} CMAKE_INCLUDE_SYSTEM_FLAG_CXX) endif() include(cmake/Platform/Common/TargetIncludeSystemDirectories_unsupported.cmake) From 64ab8d5956c7024280826dae7d63a482f60b67ee Mon Sep 17 00:00:00 2001 From: Sean Masterson Date: Thu, 4 Nov 2021 12:13:25 -0700 Subject: [PATCH 197/200] Add P0 Bloom Test Signed-off-by: Sean Masterson --- .../Atom/TestSuite_Main_Optimized.py | 4 + .../Atom/atom_utils/atom_constants.py | 3 + .../hydra_AtomEditorComponents_BloomAdded.py | 188 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py index 950bd44199..18c77391dc 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_Optimized.py @@ -14,6 +14,10 @@ from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): + @pytest.mark.test_case_id("C36525657") + class AtomEditorComponents_BloomAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_BloomAdded as test_module + @pytest.mark.test_case_id("C32078118") class AtomEditorComponents_DecalAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index c365999335..41ffaa0ce1 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -42,12 +42,14 @@ class AtomComponentProperties: Bloom component properties. Requires PostFX Layer component. - 'requires' a list of component names as strings required by this component. Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n + - 'Enable Bloom' Toggle active state of the component True/False :param property: From the last element of the property tree path. Default 'name' for component name string. :return: Full property path OR component name if no property specified. """ properties = { 'name': 'Bloom', 'requires': [AtomComponentProperties.postfx_layer()], + 'Enable Bloom': 'Controller|Configuration|Enable Bloom', } return properties[property] @@ -212,6 +214,7 @@ class AtomComponentProperties: HDR Color Grading component properties. Requires PostFX Layer component. - 'requires' a list of component names as strings required by this component. Use editor_entity_utils EditorEntity.add_components(list) to add this list of requirements.\n + - 'Enable HDR color grading' Toggle active state of the component True/False :param property: From the last element of the property tree path. Default 'name' for component name string. :return: Full property path OR component name if no property specified. """ diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py new file mode 100644 index 0000000000..bce4b86a35 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py @@ -0,0 +1,188 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +class Tests: + creation_undo = ( + "UNDO Entity creation success", + "UNDO Entity creation failed") + creation_redo = ( + "REDO Entity creation success", + "REDO Entity creation failed") + bloom_creation = ( + "Bloom Entity successfully created", + "Bloom Entity failed to be created") + bloom_component = ( + "Entity has a Bloom component", + "Entity failed to find Bloom component") + bloom_disabled = ( + "Bloom component disabled", + "Bloom component was not disabled") + postfx_layer_component = ( + "Entity has a PostFX Layer component", + "Entity did not have an PostFX Layer component") + bloom_enabled = ( + "Bloom component enabled", + "Bloom component was not enabled") + enable_bloom_parameter_enabled = ( + "Enable Bloom parameter enabled", + "Enable Bloom parameter was not enabled") + enter_game_mode = ( + "Entered game mode", + "Failed to enter game mode") + exit_game_mode = ( + "Exited game mode", + "Couldn't exit game mode") + is_visible = ( + "Entity is visible", + "Entity was not visible") + is_hidden = ( + "Entity is hidden", + "Entity was not hidden") + entity_deleted = ( + "Entity deleted", + "Entity was not deleted") + deletion_undo = ( + "UNDO deletion success", + "UNDO deletion failed") + deletion_redo = ( + "REDO deletion success", + "REDO deletion failed") + + +def AtomEditorComponents_Bloom_AddedToEntity(): + """ + Summary: + Tests the Bloom component can be added to an entity and has the expected functionality. + + Test setup: + - Wait for Editor idle loop. + - Open the "Base" level. + + Expected Behavior: + The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components. + Creation and deletion undo/redo should also work. + + Test Steps: + 1) Create an Bloom entity with no components. + 2) Add Bloom component to Bloom entity. + 3) UNDO the entity creation and component addition. + 4) REDO the entity creation and component addition. + 5) Verify Bloom component not enabled. + 6) Add PostFX Layer component since it is required by the Bloom component. + 7) Verify Bloom component is enabled. + 8) Enable the "Enable Bloom" parameter. + 9) Enter/Exit game mode. + 10) Test IsHidden. + 11) Test IsVisible. + 12) Delete Bloom entity. + 13) UNDO deletion. + 14) REDO deletion. + 15) Look for errors. + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report, Tracer, TestHelper + from Atom.atom_utils.atom_constants import AtomComponentProperties + + with Tracer() as error_tracer: + # Test setup begins. + # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. + TestHelper.init_idle() + TestHelper.open_level("", "Base") + + # Test steps begin. + # 1. Create an Bloom entity with no components. + bloom_entity = EditorEntity.create_editor_entity(AtomComponentProperties.bloom()) + Report.critical_result(Tests.bloom_creation, bloom_entity.exists()) + + # 2. Add Bloom component to Bloom entity. + bloom_component = bloom_entity.add_component(AtomComponentProperties.bloom()) + Report.critical_result(Tests.bloom_component, bloom_entity.has_component(AtomComponentProperties.bloom())) + + # 3. UNDO the entity creation and component addition. + # -> UNDO component addition. + general.undo() + # -> UNDO naming entity. + general.undo() + # -> UNDO selecting entity. + general.undo() + # -> UNDO entity creation. + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.creation_undo, not bloom_entity.exists()) + + # 4. REDO the entity creation and component addition. + # -> REDO entity creation. + general.redo() + # -> REDO selecting entity. + general.redo() + # -> REDO naming entity. + general.redo() + # -> REDO component addition. + general.redo() + general.idle_wait_frames(1) + Report.result(Tests.creation_redo, bloom_entity.exists()) + + # 5. Verify Bloom component not enabled. + Report.result(Tests.bloom_disabled, not bloom_component.is_enabled()) + + # 6. Add PostFX Layer component since it is required by the Bloom component. + bloom_entity.add_component(AtomComponentProperties.postfx_layer()) + Report.result( + Tests.postfx_layer_component, + bloom_entity.has_component(AtomComponentProperties.postfx_layer())) + + # 7. Verify Bloom component is enabled. + Report.result(Tests.bloom_enabled, bloom_component.is_enabled()) + + # 8. Enable the "Enable Bloom" parameter. + bloom_component.set_component_property_value(AtomComponentProperties.bloom('Enable Bloom'), True) + Report.result( + Tests.enable_bloom_parameter_enabled, + bloom_component.get_component_property_value(AtomComponentProperties.bloom('Enable Bloom')) is True) + + # 9. Enter/Exit game mode. + TestHelper.enter_game_mode(Tests.enter_game_mode) + general.idle_wait_frames(1) + TestHelper.exit_game_mode(Tests.exit_game_mode) + + # 10. Test IsHidden. + bloom_entity.set_visibility_state(False) + Report.result(Tests.is_hidden, bloom_entity.is_hidden() is True) + + # 11. Test IsVisible. + bloom_entity.set_visibility_state(True) + general.idle_wait_frames(1) + Report.result(Tests.is_visible, bloom_entity.is_visible() is True) + + # 12. Delete Bloom entity. + bloom_entity.delete() + Report.result(Tests.entity_deleted, not bloom_entity.exists()) + + # 13. UNDO deletion. + general.undo() + Report.result(Tests.deletion_undo, bloom_entity.exists()) + + # 14. REDO deletion. + general.redo() + Report.result(Tests.deletion_redo, not bloom_entity.exists()) + + # 15. Look for errors and asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(AtomEditorComponents_Bloom_AddedToEntity) From bbeefe43b836a67ccd3eca0ca4775600c9684edd Mon Sep 17 00:00:00 2001 From: Sean Masterson Date: Thu, 4 Nov 2021 13:52:54 -0700 Subject: [PATCH 198/200] Added extra line above class Tests Signed-off-by: Sean Masterson --- .../Atom/tests/hydra_AtomEditorComponents_BloomAdded.py | 1 + 1 file changed, 1 insertion(+) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py index bce4b86a35..56b22eb20d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py @@ -5,6 +5,7 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ + class Tests: creation_undo = ( "UNDO Entity creation success", From 0c97c879c108073b58ae6e9276212b2796170ef6 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 13:58:30 -0700 Subject: [PATCH 199/200] remove the main suite optimized jobs from CMakeLists.txt since its causing a false build failure on AR Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- .../Gem/PythonTests/Atom/CMakeLists.txt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt index ff3cd5c465..87a66c880e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt @@ -20,19 +20,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED) COMPONENT Atom ) - ly_add_pytest( - NAME AutomatedTesting::Atom_TestSuite_Main_Optimized - TEST_SUITE main - PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py - TEST_SERIAL - TIMEOUT 600 - RUNTIME_DEPENDENCIES - AssetProcessor - AutomatedTesting.Assets - Editor - COMPONENT - Atom - ) ly_add_pytest( NAME AutomatedTesting::Atom_TestSuite_Sandbox TEST_SUITE sandbox From 6bae0bca7e5a0947615a1814da4b1c397660e095 Mon Sep 17 00:00:00 2001 From: jromnoa <80134229+jromnoa@users.noreply.github.com> Date: Thu, 4 Nov 2021 15:08:02 -0700 Subject: [PATCH 200/200] add new bloom test to updated Main Suite test file since optimized main suite test file is removed Signed-off-by: jromnoa <80134229+jromnoa@users.noreply.github.com> --- AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index 62a402d9c4..cce9a27da6 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -13,6 +13,10 @@ from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): + @pytest.mark.test_case_id("C36525657") + class AtomEditorComponents_BloomAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponents_BloomAdded as test_module + @pytest.mark.test_case_id("C32078118") class AtomEditorComponents_DecalAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module