From 5231cb9b53b86d442effdbbfd46292b3f20732d5 Mon Sep 17 00:00:00 2001 From: "T.J. McGrath-Daly" Date: Fri, 15 Oct 2021 10:58:31 +0800 Subject: [PATCH 01/36] Shortcut keys issue Signed-off-by: T.J. McGrath-Daly --- .../Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp index b75fb71060..952b3134b6 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -532,7 +532,7 @@ namespace EMStudio QAction* characterLayoutAction = new QAction( "Character", this); - characterLayoutAction->setShortcut(Qt::Key_1 | Qt::AltModifier); + characterLayoutAction->setShortcut(Qt::Key_3 | Qt::AltModifier); m_shortcutManager->RegisterKeyboardShortcut(characterLayoutAction, layoutGroupName, false); connect(characterLayoutAction, &QAction::triggered, [this]{ m_applicationMode->setCurrentIndex(2); }); addAction(characterLayoutAction); From 5dc97e7e4b5e9272f4940628833315007a060c8b Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Tue, 11 Jan 2022 16:34:22 -0800 Subject: [PATCH 02/36] Fix Prefab instance assets not preloading PrefabCatchmentProcessor::ProcessPrefab was no longer updating the ProcessedObjectStore's referenced object list, this change exposes the referenced asset list in the new PrefabDocument API and uses them to update the referenced asset list. Signed-off-by: Nicholas Van Sickle --- .../Prefab/Spawnable/PrefabCatchmentProcessor.cpp | 1 + .../Prefab/Spawnable/PrefabDocument.cpp | 12 +++++++++++- .../Prefab/Spawnable/PrefabDocument.h | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp index 40cd52cac8..a5ca034c36 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp @@ -64,6 +64,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer)); AZ_Assert(spawnable, "Failed to create a new spawnable."); + object.GetReferencedAssets() = prefab.GetReferencedAssets(); Instance& instance = prefab.GetInstance(); // Resolve entity aliases that store PrefabDOM information to use the spawnable instead. This is done before the entities are // moved from the instance as they'd otherwise can't be found. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp index 04fdea30d2..230c2226cd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp @@ -124,12 +124,22 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils return *m_instance; } + AZStd::vector>& PrefabDocument::GetReferencedAssets() + { + return m_referencedAssets; + } + + const AZStd::vector>& PrefabDocument::GetReferencedAssets() const + { + return m_referencedAssets; + } + bool PrefabDocument::ConstructInstanceFromPrefabDom(const PrefabDom& prefab) { using namespace AzToolsFramework::Prefab; m_instance->Reset(); - if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, PrefabDomUtils::LoadFlags::AssignRandomEntityId)) + if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, m_referencedAssets, PrefabDomUtils::LoadFlags::AssignRandomEntityId)) { return true; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h index 215daf7f71..661dba5edf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h @@ -53,12 +53,16 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AzToolsFramework::Prefab::Instance& GetInstance(); const AzToolsFramework::Prefab::Instance& GetInstance() const; + AZStd::vector>& GetReferencedAssets(); + const AZStd::vector>& GetReferencedAssets() const; + private: bool ConstructInstanceFromPrefabDom(const PrefabDom& prefab); mutable PrefabDom m_dom; AZStd::unique_ptr m_instance; AZStd::string m_name; + AZStd::vector> m_referencedAssets; mutable bool m_isDirty{ false }; }; } // namespace AzToolsFramework::Prefab::PrefabConversionUtils From b772d7b3e8abd15acaf1db40d5a79357927f014d Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 11:10:34 -0800 Subject: [PATCH 03/36] Removing multiplayer script canvas translation files from the scriptcanvas gem; these will eventually move into AutomatedTesting project once repopulated (if needed). Signed-off-by: Gene Walters --- ...orityToAutonomousNoParamsNotifyEvent.names | 50 -- .../AuthorityToAutonomousNotifyEvent.names | 56 --- ...AuthorityToClientNoParamsNotifyEvent.names | 50 -- .../AuthorityToClientNotifyEvent.names | 56 --- ...nomousToAuthorityNoParamsNotifyEvent.names | 50 -- .../AutonomousToAuthorityNotifyEvent.names | 56 --- .../ServerToAuthorityNoParamNotifyEvent.names | 50 -- .../ServerToAuthorityNotifyEvent.names | 56 --- .../Classes/NetworkTestPlayerComponent.names | 438 ------------------ ...tworkTestPlayerComponentNetworkInput.names | 129 ------ 10 files changed, 991 deletions(-) delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names deleted file mode 100644 index 216212ca4a..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToAutonomousNoParams Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Autonomous No Params Notify Event" - }, - "slots": [ - { - "base": "AuthorityToAutonomousNoParams Notify Event", - "details": { - "name": "AuthorityToAutonomousNoParams Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names deleted file mode 100644 index 50c0ec6013..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToAutonomous Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Autonomous Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "AuthorityToAutonomous Notify Event", - "details": { - "name": "AuthorityToAutonomous Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names deleted file mode 100644 index bf5b975d63..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToClientNoParams Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Client No Params Notify Event" - }, - "slots": [ - { - "base": "AuthorityToClientNoParams Notify Event", - "details": { - "name": "AuthorityToClientNoParams Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names deleted file mode 100644 index d3ba2e9299..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToClient Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Client Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "AuthorityToClient Notify Event", - "details": { - "name": "AuthorityToClient Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names deleted file mode 100644 index ba5f7aec0c..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "AutonomousToAuthorityNoParams Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Autonomous To Authority No Params Notify Event" - }, - "slots": [ - { - "base": "AutonomousToAuthorityNoParams Notify Event", - "details": { - "name": "AutonomousToAuthorityNoParams Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names deleted file mode 100644 index 73566d177e..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "AutonomousToAuthority Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Autonomous To Authority Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "AutonomousToAuthority Notify Event", - "details": { - "name": "AutonomousToAuthority Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names deleted file mode 100644 index b6694211cd..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "ServerToAuthorityNoParam Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Server To Authority No Param Notify Event" - }, - "slots": [ - { - "base": "ServerToAuthorityNoParam Notify Event", - "details": { - "name": "ServerToAuthorityNoParam Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names deleted file mode 100644 index 71ab303260..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "ServerToAuthority Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Server To Authority Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "ServerToAuthority Notify Event", - "details": { - "name": "ServerToAuthority Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names deleted file mode 100644 index 22636e0453..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names +++ /dev/null @@ -1,438 +0,0 @@ -{ - "entries": [ - { - "base": "NetworkTestPlayerComponent", - "context": "BehaviorClass", - "variant": "", - "details": { - "name": "Network Test Player Component" - }, - "methods": [ - { - "base": "AutonomousToAuthority", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority is invoked" - }, - "details": { - "name": "Autonomous To Authority" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "ServerToAuthority", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority is invoked" - }, - "details": { - "name": "Server To Authority" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority By Entity Id is invoked" - }, - "details": { - "name": "Autonomous To Authority By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "ServerToAuthorityByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority By Entity Id is invoked" - }, - "details": { - "name": "Server To Authority By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityNoParams", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority No Params" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority No Params is invoked" - }, - "details": { - "name": "Autonomous To Authority No Params" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - }, - { - "base": "AuthorityToAutonomous", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous is invoked" - }, - "details": { - "name": "Authority To Autonomous" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "AuthorityToClientNoParams", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client No Params" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client No Params is invoked" - }, - "details": { - "name": "Authority To Client No Params" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - }, - { - "base": "AuthorityToClientByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client By Entity Id is invoked" - }, - "details": { - "name": "Authority To Client By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AuthorityToClient", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client is invoked" - }, - "details": { - "name": "Authority To Client" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "AuthorityToAutonomousNoParams", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous No Params" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous No Params is invoked" - }, - "details": { - "name": "Authority To Autonomous No Params" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - }, - { - "base": "ServerToAuthorityNoParamByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority No Param By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority No Param By Entity Id is invoked" - }, - "details": { - "name": "Server To Authority No Param By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "AuthorityToClientNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client No Params By Entity Id is invoked" - }, - "details": { - "name": "Authority To Client No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "AuthorityToAutonomousByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous By Entity Id is invoked" - }, - "details": { - "name": "Authority To Autonomous By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority No Params By Entity Id is invoked" - }, - "details": { - "name": "Autonomous To Authority No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "AuthorityToAutonomousNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous No Params By Entity Id is invoked" - }, - "details": { - "name": "Authority To Autonomous No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "ServerToAuthorityNoParam", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority No Param" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority No Param is invoked" - }, - "details": { - "name": "Server To Authority No Param" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names deleted file mode 100644 index d8c016db0f..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names +++ /dev/null @@ -1,129 +0,0 @@ -{ - "entries": [ - { - "base": "NetworkTestPlayerComponentNetworkInput", - "context": "BehaviorClass", - "variant": "", - "details": { - "name": "Network Test Player Component Network Input" - }, - "methods": [ - { - "base": "CreateFromValues", - "context": "NetworkTestPlayerComponentNetworkInput", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Create From Values" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Create From Values is invoked" - }, - "details": { - "name": "Create From Values" - }, - "params": [ - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "left Right" - } - } - ], - "results": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - } - ] - }, - { - "base": "GetFwdBack", - "details": { - "name": "Get Fwd Back" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - } - ], - "results": [ - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Fwd Back" - } - } - ] - }, - { - "base": "SetFwdBack", - "details": { - "name": "Set Fwd Back" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Fwd Back" - } - } - ] - }, - { - "base": "GetLeftRight", - "details": { - "name": "Get Left Right" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - } - ], - "results": [ - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Left Right" - } - } - ] - }, - { - "base": "SetLeftRight", - "details": { - "name": "Set Left Right" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Left Right" - } - } - ] - } - ] - } - ] -} \ No newline at end of file From 561ff40c8154c335ad435086923a20aefa66a2d5 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 11:13:10 -0800 Subject: [PATCH 04/36] Creating a new multiplayer component which we'll assign to a networked level entity (as opposed to a network player). Signed-off-by: Gene Walters --- ...workTestLevelEntityComponent.AutoComponent.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml new file mode 100644 index 0000000000..2fd196a2f6 --- /dev/null +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml @@ -0,0 +1,15 @@ + + + + + + + + + From ee3196d64a9d31929951ad60134b22dbe4b1db02 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 11:31:45 -0800 Subject: [PATCH 05/36] Removed an RPC that's now being used inside the NetLevelEntity autocomponent Signed-off-by: Gene Walters --- .../Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml index 251d2b25af..b4dd35d741 100644 --- a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml @@ -29,8 +29,6 @@ - - From 3b84049a1d12409d0cfa7bffcd5a059cc592915f Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:18:06 -0800 Subject: [PATCH 06/36] Adding NetworkTestLevelEntityComponent to cmake for compilation Signed-off-by: Gene Walters --- AutomatedTesting/Gem/Code/automatedtesting_files.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake index eb619104a4..1f6dbbd772 100644 --- a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake +++ b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake @@ -12,4 +12,5 @@ set(FILES Source/AutomatedTestingSystemComponent.cpp Source/AutomatedTestingSystemComponent.h Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml + Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml ) From 4e811d5af8383844889ed45f903b8650319c0d08 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:19:59 -0800 Subject: [PATCH 07/36] Small update: adding the component type to a warning in order to help debug what component is failing Signed-off-by: Gene Walters --- Code/Framework/AzCore/AzCore/Component/Component.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/Component.cpp b/Code/Framework/AzCore/AzCore/Component/Component.cpp index c9829c6dd8..c11e4ef69f 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Component.cpp @@ -49,7 +49,7 @@ namespace AZ return m_entity->GetId(); } - AZ_Warning("System", false, "Can't get component %p entity ID as it is not attached to an entity yet!", this); + AZ_Warning("System", false, "Can't get component (type: %s, addr: %p) entity ID as it is not attached to an entity yet!", RTTI_GetTypeName(), this); return EntityId(); } @@ -60,7 +60,7 @@ namespace AZ return NamedEntityId(m_entity->GetId(), m_entity->GetName()); } - AZ_Warning("System", false, "Can't get component %p entity ID as it is not attached to an entity yet!", this); + AZ_Warning("System", false, "Can't get component (type: %s, addr: %p) entity ID as it is not attached to an entity yet!", RTTI_GetTypeName(), this); return NamedEntityId(); } From a635e935e3893ad974e92a52fe4c71a115f1a325 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:20:46 -0800 Subject: [PATCH 08/36] minor typo fix on code warning Signed-off-by: Gene Walters --- Code/Framework/AzCore/AzCore/Component/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index c5cda98f2c..db9ead93ad 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -230,7 +230,7 @@ namespace AZ EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id); - AZ_Assert(m_state == State::Active, "Component should be in Active state to br Deactivated!"); + AZ_Assert(m_state == State::Active, "Component should be in Active state to be Deactivated!"); SetState(State::Deactivating); for (ComponentArrayType::reverse_iterator it = m_components.rbegin(); it != m_components.rend(); ++it) From 49a0c78013391ca62424560a05a59434ff30c8f9 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:33:28 -0800 Subject: [PATCH 09/36] Check if transform component is attached to an entity before sending out notifications that rely upon having an entity; this stops runtime warnings when calling GetEntityId() Signed-off-by: Gene Walters --- .../Components/TransformComponent.cpp | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 809f664a10..e4e0ea08b2 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -585,21 +585,25 @@ namespace AzFramework EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnParentChanged, oldParent, parentId); m_parentChangedEvent.Signal(oldParent, parentId); - if (oldParent != parentId) // Don't send removal notification while activating. + // Check if we're attached to an entity; the following notifications rely upon having a valid entity id + if (m_entity != nullptr) { - EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId()); - auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent); - if (oldParentTransform) + if (oldParent != parentId) // Don't send removal notification while activating. { - oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId()); + EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId()); + auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent); + if (oldParentTransform) + { + oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId()); + } } - } - EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId()); - auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId); - if (newParentTransform) - { - newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId()); + EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId()); + auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId); + if (newParentTransform) + { + newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId()); + } } } From ffde76208154d9e6c20f44f1d151eff82e763e9e Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:43:39 -0800 Subject: [PATCH 10/36] Minor comment tweak, and code readability Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorConnection.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index c8c1ed15bd..3ae4eb6444 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -100,8 +100,8 @@ namespace Multiplayer { // Editor Server Init is intended for non-release targets m_byteStream.Write(packet.GetAssetData().GetSize(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); - - // In case if this is the last update, process the byteStream buffer. Otherwise more packets are expected + + // If this is the last update then process the byteStream buffer. Otherwise more packets are expected if (packet.GetLastUpdate()) { // This is the last expected packet @@ -150,9 +150,8 @@ namespace Multiplayer AZ::Interface::Get()->BuildSpawnablesList(); // Load the level via the root spawnable that was registered - const AZ::CVarFixedString loadLevelString = "LoadLevel Root.spawnable"; const auto console = AZ::Interface::Get(); - console->PerformCommand(loadLevelString.c_str()); + console->PerformCommand("LoadLevel Root.spawnable"); // Setup the normal multiplayer connection AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer); From c8e5bcc901c989c12c3e485df9427d0546d8d7ac Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 14 Jan 2022 12:01:32 -0800 Subject: [PATCH 11/36] Dont allow spawning netbound entities by default, we first need to initialize multiplayer and know our network agent type (dedicated-server/client-server/client). This will stop the editor playmode (which doesn't init multiplayer until it connects to the server) from spawning netbound entities Signed-off-by: Gene Walters --- Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index dd2e7956ca..47238cc729 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -184,7 +184,7 @@ namespace Multiplayer double m_serverSendAccumulator = 0.0; float m_renderBlendFactor = 0.0f; float m_tickFactor = 0.0f; - bool m_spawnNetboundEntities = true; + bool m_spawnNetboundEntities = false; #if !defined(AZ_RELEASE_BUILD) MultiplayerEditorConnection m_editorConnectionListener; From e4bd28f636d9421bb1807bac8c1586afa26afe37 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 14 Jan 2022 13:48:37 -0800 Subject: [PATCH 12/36] Update NetworkSpawnableLibrary to only hold onto network.spawnables (instead of all spawnables) Signed-off-by: Gene Walters --- .../Source/NetworkEntity/NetworkSpawnableLibrary.cpp | 4 ++-- .../Code/Source/NetworkEntity/NetworkSpawnableLibrary.h | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp index f60778dbb4..7fb7bfdc39 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace Multiplayer @@ -42,7 +41,8 @@ namespace Multiplayer auto enumerateCallback = [this](const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) { - if (info.m_assetType == AZ::AzTypeInfo::Uuid()) + if (info.m_assetType == AZ::AzTypeInfo::Uuid() && + info.m_relativePath.ends_with(".network.spawnable")) { ProcessSpawnableAsset(info.m_relativePath, id); } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h index 0fc3ae07cc..db22ccf9de 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h @@ -22,13 +22,16 @@ namespace Multiplayer NetworkSpawnableLibrary(); ~NetworkSpawnableLibrary(); - - /// INetworkSpawnableLibrary overrides. + + //! INetworkSpawnableLibrary overrides. + //! @{ + // Iterates over all assets (on-disk and in-memory) and stores any spawnables that are "network.spawnables" + // This allows us to look up network spawnable assets by name or id for later use void BuildSpawnablesList() override; void ProcessSpawnableAsset(const AZStd::string& relativePath, AZ::Data::AssetId id) override; AZ::Name GetSpawnableNameFromAssetId(AZ::Data::AssetId assetId) override; AZ::Data::AssetId GetAssetIdByName(AZ::Name name) override; - + //! @} private: AZStd::unordered_map m_spawnables; From 786d6b5f85e7c1f5bf1f9ce8d24a0571c8d06ba1 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 18 Jan 2022 10:22:31 -0800 Subject: [PATCH 13/36] minor code readability tweak Signed-off-by: Gene Walters --- .../Code/Source/NetworkEntity/NetworkEntityManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index fa524d464a..0a6aeea8a8 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -542,7 +542,7 @@ namespace Multiplayer optionalArgs.m_preInsertionCallback = [netSpawnableName, rootTransform = transform] (AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView entities) { - bool shouldUpdateTransform = (rootTransform.IsClose(AZ::Transform::Identity()) == false); + const bool shouldUpdateTransform = !rootTransform.IsClose(AZ::Transform::Identity()); for (uint32_t netEntityIndex = 0, entitiesSize = aznumeric_cast(entities.size()); netEntityIndex < entitiesSize; ++netEntityIndex) From b3d996ea230ce78293eef87959cebd349d84e6d2 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 20 Jan 2022 08:32:02 -0800 Subject: [PATCH 14/36] Adding automated test to ensure scripts attached to net-level-entities are started on the server Signed-off-by: Gene Walters --- ...TestLevelEntityComponent.AutoComponent.xml | 15 + ...tworkTestPlayerComponent.AutoComponent.xml | 2 - .../Gem/Code/automatedtesting_files.cmake | 1 + .../Multiplayer/TestSuite_Sandbox.py | 4 + .../Multiplayer_SimpleNetworkLevelEntity.py | 79 +++ .../SimpleNetworkLevelEntity/Player.prefab | 151 +++++ .../SimpleNetworkLevelEntity.prefab | 580 ++++++++++++++++++ .../SimpleNetworkLevelEntity.scriptcanvas | 228 +++++++ .../SimpleNetworkLevelEntity/tags.txt | 12 + 9 files changed, 1070 insertions(+), 2 deletions(-) create mode 100644 AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml create mode 100644 AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml new file mode 100644 index 0000000000..2fd196a2f6 --- /dev/null +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml index 251d2b25af..b4dd35d741 100644 --- a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml @@ -29,8 +29,6 @@ - - diff --git a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake index eb619104a4..1f6dbbd772 100644 --- a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake +++ b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake @@ -12,4 +12,5 @@ set(FILES Source/AutomatedTestingSystemComponent.cpp Source/AutomatedTestingSystemComponent.h Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml + Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml ) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py index 8c5f33993d..56c2608762 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py @@ -35,3 +35,7 @@ class TestAutomation(TestAutomationBase): def test_Multiplayer_AutoComponent_RPC(self, request, workspace, editor, launcher_platform): from .tests import Multiplayer_AutoComponent_RPC as test_module self._run_prefab_test(request, workspace, editor, test_module) + + def test_Multiplayer_SimpleNetworkLevelEntity(self, request, workspace, editor, launcher_platform): + from .tests import Multiplayer_SimpleNetworkLevelEntity as test_module + self._run_prefab_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py new file mode 100644 index 0000000000..da332f9085 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -0,0 +1,79 @@ +""" +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 level entities with network bindings are properly replicated. +# Note: This test should be ran on a fresh editor run; some bugs with spawnables occur only on the first editor play-mode. + + +# fmt: off +class TestSuccessFailTuples(): + 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") +# fmt: on + + +def Multiplayer_SimpleNetworkLevelEntity(): + r""" + Summary: + Runs a test to make sure that network entities in a level function and are replicated to clients as expecte + + Level Description: + - Static + 1. NetLevelEntity. This is a networked entity which has a script attached to ensure it's replicated. + + + Expected Outcome: + We should see logs stating that the net-sync'd level entity exists on both server and client. + + :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 + + level_name = "SimpleNetworkLevelEntity" + 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(TestSuccessFailTuples.enter_game_mode, player_prefab_path.lower()) + + # 3) Make sure the network player was spawned + player_id = general.find_game_entity(player_prefab_name) + Report.critical_result(TestSuccessFailTuples.find_network_player, player_id.IsValid()) + + # 4) Check the editor logs for network spawnable errors + ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 1.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this doesn't happen. + helper.fail_if_log_line_found('NetworkEntityManager', "RequestNetSpawnableInstantiation: Requested spawnable Root.network.spawnable doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable", section_tracer.errors, ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS) + + # 5) Ensure the script graph attached to the level entity is running on both client and server + SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS = 0.25 + # Check Server + helper.succeed_if_log_line_found('EditorServer', "Script: SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) + # Check Editor/Client (Uncomment once script asset preload is working properly LYN-9136) + # helper.succeed_if_log_line_found('Script', "SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) # Client + + + # Exit game mode + helper.exit_game_mode(TestSuccessFailTuples.exit_game_mode) + + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(Multiplayer_SimpleNetworkLevelEntity) diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab new file mode 100644 index 0000000000..975319a516 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab @@ -0,0 +1,151 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "Player", + "Components": { + "Component_[10626669441604518614]": { + "$type": "EditorPrefabComponent", + "Id": 10626669441604518614 + }, + "Component_[15284109105474306026]": { + "$type": "EditorVisibilityComponent", + "Id": 15284109105474306026 + }, + "Component_[1884250773831675865]": { + "$type": "SelectionComponent", + "Id": 1884250773831675865 + }, + "Component_[3027124663594865592]": { + "$type": "EditorInspectorComponent", + "Id": 3027124663594865592 + }, + "Component_[3314300526416851038]": { + "$type": "EditorEntitySortComponent", + "Id": 3314300526416851038, + "Child Entity Order": [ + "Entity_[1340484004600]" + ] + }, + "Component_[5583377204116393478]": { + "$type": "EditorEntityIconComponent", + "Id": 5583377204116393478 + }, + "Component_[5897955848881060165]": { + "$type": "EditorLockComponent", + "Id": 5897955848881060165 + }, + "Component_[6405389103180201977]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 6405389103180201977, + "Parent Entity": "" + }, + "Component_[7695912346724202125]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 7695912346724202125 + }, + "Component_[775363990560391238]": { + "$type": "EditorOnlyEntityComponent", + "Id": 775363990560391238 + }, + "Component_[904355854135646057]": { + "$type": "EditorPendingCompositionComponent", + "Id": 904355854135646057 + } + } + }, + "Entities": { + "Entity_[1340484004600]": { + "Id": "Entity_[1340484004600]", + "Name": "Player", + "Components": { + "Component_[12294726333564087591]": { + "$type": "SelectionComponent", + "Id": 12294726333564087591 + }, + "Component_[13587084088242540786]": { + "$type": "EditorInspectorComponent", + "Id": 13587084088242540786, + "ComponentOrderEntryArray": [ + { + "ComponentId": 6819443882832501114 + }, + { + "ComponentId": 4337571454344109612, + "SortIndex": 1 + }, + { + "ComponentId": 16457408099527309065, + "SortIndex": 2 + }, + { + "ComponentId": 5577505593558922067, + "SortIndex": 3 + } + ] + }, + "Component_[14335168881008289852]": { + "$type": "EditorEntitySortComponent", + "Id": 14335168881008289852 + }, + "Component_[16308902899170829847]": { + "$type": "EditorVisibilityComponent", + "Id": 16308902899170829847 + }, + "Component_[16457408099527309065]": { + "$type": "GenericComponentWrapper", + "Id": 16457408099527309065, + "m_template": { + "$type": "Multiplayer::NetworkTransformComponent" + } + }, + "Component_[16541569566865026527]": { + "$type": "EditorOnlyEntityComponent", + "Id": 16541569566865026527 + }, + "Component_[2002761223483048905]": { + "$type": "EditorPendingCompositionComponent", + "Id": 2002761223483048905 + }, + "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_[8838623765985560328]": { + "$type": "EditorEntityIconComponent", + "Id": 8838623765985560328 + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab new file mode 100644 index 0000000000..abe458246a --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab @@ -0,0 +1,580 @@ +{ + "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, + "Child Entity Order": [ + "Entity_[1176639161715]", + "Entity_[806656324666]" + ] + }, + "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 + }, + "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": 9021008456353177945 + } + } + }, + "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, + "Child Entity Order": [ + "Entity_[1155164325235]", + "Entity_[1180934129011]", + "Entity_[1168049227123]", + "Entity_[1163754259827]", + "Entity_[1159459292531]" + ] + }, + "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 + } + } + }, + "Entity_[806656324666]": { + "Id": "Entity_[806656324666]", + "Name": "NetEntity", + "Components": { + "Component_[10272449525230713408]": { + "$type": "EditorScriptCanvasComponent", + "Id": 10272449525230713408, + "m_name": "SimpleNetworkLevelEntity.scriptcanvas", + "runtimeDataIsValid": true, + "runtimeDataOverrides": { + "source": { + "id": "{C8F17F94-1225-5FFB-A89F-7C5546FF9DD2}", + "path": "C:/prj/o3de/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas" + } + }, + "sourceHandle": { + "id": "{C8F17F94-1225-5FFB-A89F-7C5546FF9DD2}", + "path": "C:/prj/o3de/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas" + } + }, + "Component_[12604265186664827718]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 12604265186664827718 + }, + "Component_[12971088454284742740]": { + "$type": "EditorInspectorComponent", + "Id": 12971088454284742740 + }, + "Component_[13637345797899267673]": { + "$type": "EditorPendingCompositionComponent", + "Id": 13637345797899267673 + }, + "Component_[14691827217729577086]": { + "$type": "EditorVisibilityComponent", + "Id": 14691827217729577086 + }, + "Component_[17587769654029626028]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 17587769654029626028, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}", + "subId": 284780167 + }, + "assetHint": "models/sphere.azmodel" + } + } + } + }, + "Component_[3583806849894952953]": { + "$type": "EditorOnlyEntityComponent", + "Id": 3583806849894952953 + }, + "Component_[3992057042487734240]": { + "$type": "EditorLockComponent", + "Id": 3992057042487734240 + }, + "Component_[4205899043279271481]": { + "$type": "GenericComponentWrapper", + "Id": 4205899043279271481, + "m_template": { + "$type": "Multiplayer::NetworkTransformComponent" + } + }, + "Component_[4416976521140638764]": { + "$type": "EditorEntityIconComponent", + "Id": 4416976521140638764 + }, + "Component_[4951162661196722987]": { + "$type": "EditorEntitySortComponent", + "Id": 4951162661196722987 + }, + "Component_[57491843687005111]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 57491843687005111, + "Parent Entity": "Entity_[1146574390643]", + "Transform Data": { + "Translate": [ + -0.010266244411468506, + 0.09999752044677734, + 0.4922151565551758 + ] + } + }, + "Component_[7427201282284088219]": { + "$type": "SelectionComponent", + "Id": 7427201282284088219 + }, + "Component_[9767802049284917261]": { + "$type": "GenericComponentWrapper", + "Id": 9767802049284917261, + "m_template": { + "$type": "NetBindComponent" + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas new file mode 100644 index 0000000000..7f41ed9af2 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas @@ -0,0 +1,228 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "ScriptCanvasData", + "ClassData": { + "m_scriptCanvas": { + "Id": { + "id": 5227099818161821361 + }, + "Name": "Script Canvas Graph", + "Components": { + "Component_[14745706451564425001]": { + "$type": "EditorGraphVariableManagerComponent", + "Id": 14745706451564425001 + }, + "Component_[6188351434280490877]": { + "$type": "EditorGraph", + "Id": 6188351434280490877, + "m_graphData": { + "m_nodes": [ + { + "Id": { + "id": 1181151842701 + }, + "Name": "SC-Node(Print)", + "Components": { + "Component_[11204048151736284490]": { + "$type": "Print", + "Id": 11204048151736284490, + "Slots": [ + { + "id": { + "m_id": "{A417FF98-493E-4DE6-AD3A-E7A1848661E4}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Input signal", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{38BC2AB1-7654-407E-9903-4B5D77EDB6F3}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "m_format": "SimpleNetworkLevelEntity: On Graph Start\n", + "m_unresolvedString": [ + "SimpleNetworkLevelEntity: On Graph Start\n" + ] + } + } + }, + { + "Id": { + "id": 811784655245 + }, + "Name": "SC-Node(Start)", + "Components": { + "Component_[2986280341871382503]": { + "$type": "Start", + "Id": 2986280341871382503, + "Slots": [ + { + "id": { + "m_id": "{61FBEFC6-23BA-4A53-89BF-D0D0E834608C}" + }, + "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": 2521181639053 + }, + "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(Print: In)", + "Components": { + "Component_[16295428600276205051]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 16295428600276205051, + "sourceEndpoint": { + "nodeId": { + "id": 811784655245 + }, + "slotId": { + "m_id": "{61FBEFC6-23BA-4A53-89BF-D0D0E834608C}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 1181151842701 + }, + "slotId": { + "m_id": "{A417FF98-493E-4DE6-AD3A-E7A1848661E4}" + } + } + } + } + } + ] + }, + "m_assetType": "{00000000-0000-0000-D033-B2489A010000}", + "versionData": { + "_grammarVersion": 1, + "_runtimeVersion": 1, + "_fileVersion": 1 + }, + "GraphCanvasData": [ + { + "Key": { + "id": 811784655245 + }, + "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": [ + 340.0, + 180.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{6045F7F7-02B0-442A-96C7-A0CBCEFF7275}" + } + } + } + }, + { + "Key": { + "id": 1181151842701 + }, + "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": [ + 580.0, + 180.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{589F773E-D82A-4EDD-AEBD-3ADC07FC67CE}" + } + } + } + }, + { + "Key": { + "id": 5227099818161821361 + }, + "Value": { + "ComponentData": { + "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { + "$type": "SceneComponentSaveData" + } + } + } + } + ], + "StatisticsHelper": { + "InstanceCounter": [ + { + "Key": 4199610336680704683, + "Value": 1 + }, + { + "Key": 10684225535275896474, + "Value": 1 + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/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 3c879d59676d513da30b40df9fb8c3abeab0f2e6 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 20 Jan 2022 08:45:35 -0800 Subject: [PATCH 15/36] fix pytest typos Signed-off-by: Gene Walters --- .../Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py index da332f9085..aadf12d7e3 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -21,11 +21,11 @@ class TestSuccessFailTuples(): def Multiplayer_SimpleNetworkLevelEntity(): r""" Summary: - Runs a test to make sure that network entities in a level function and are replicated to clients as expecte + Test to make sure that network entities in a level function and are replicated to clients as expected Level Description: - Static - 1. NetLevelEntity. This is a networked entity which has a script attached to ensure it's replicated. + 1. NetLevelEntity. This is a networked entity which has a script attached which prints logs to ensure it's replicated. Expected Outcome: From 6fde1389bf6536d1196517c5df3686d4f5ef7078 Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Thu, 20 Jan 2022 13:35:08 -0800 Subject: [PATCH 16/36] adding editor level load automation script Signed-off-by: Neil Widmaier --- .../Atom/tests/hydra_Atom_LevelLoadTest.py | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py new file mode 100644 index 0000000000..77886e2123 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py @@ -0,0 +1,85 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +def Atom_LevelLoadTest(): + """ + Summary: + Loads all graphics levels within the AutomatedTesting project in editor. For each level this script will verify that + the level loads, and can enter/exit gameplay without crashing the editor. + + Test setup: + - Store all available levels in a list. + - Set up a for loop to run all checks for each level. + + Expected Behavior: + Test verifies that each level loads, enters/exits game mode, and reports success for all test actions. + + Test Steps for each level: + 1) Create tuple with level load success and failure messages + 2) Open the level using the python test tools command + 3) Verify level is loaded using a separate command, and report success/failure + 4) Create tuple with success and failure messages for entering gameplay + 5) Enter gameplay and report result + 6) Create tuple with success and failure messages for exiting gameplay + 7) Exit Gameplay and report result + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + level_list = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest", "Sponza"] + + with Tracer() as error_tracer: + # + + for level in level_list: + + # 1. Create tuple with level load success and failure messages + level_check_tupple = (f"loaded {level}", f"failed to load {level}") + + # 2. Open the level using the python test tools command + TestHelper.init_idle() + TestHelper.open_level("graphics", level) + + # 3. Verify level is loaded using a separate command, and report success/failure + load_success = general.get_current_level_name() + Report.info(load_success) + if load_success == level: + level_match = True + else: + level_match = False + Report.info(level_match) + Report.result(level_check_tupple, level_match) + + # 4. Create tuple with success and failure messages for entering gameplay + Enter_game_mode_tupple = (f"{level} entered gameplay successfully ", f"{level} failed to enter gameplay") + + # 5. Enter gameplay and report result + TestHelper.enter_game_mode(Enter_game_mode_tupple) + + # 6. Create tuple with success and failure messages for exiting gameplay + Exit_game_mode_tupple = (f"{level} exited gameplay successfully ", f"{level} failed to exit gameplay") + + # 7. Exit Gameplay and report result + TestHelper.exit_game_mode(Exit_game_mode_tupple) + + + # 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(Atom_LevelLoadTest) From b98b240a4001a7928d89facc9303aa9e20453568 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Thu, 20 Jan 2022 18:16:51 -0800 Subject: [PATCH 17/36] Entity Reference P1 initial tests Signed-off-by: Scott Murray --- .../Atom/atom_utils/atom_constants.py | 2 + ...omEditorComponents_EntityReferenceAdded.py | 101 ++++++++++++++++-- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index e6d6ac7fb1..c3404c1e94 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -195,11 +195,13 @@ class AtomComponentProperties: def entity_reference(property: str = 'name') -> str: """ Entity Reference component properties. + - 'EntityIdReferences' component container of entityId references. Initially empty. :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': 'Entity Reference', + 'EntityIdReferences': 'Controller|Configuration|EntityIdReferences', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index dddcca64fa..9dc4869f66 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -9,37 +9,55 @@ SPDX-License-Identifier: Apache-2.0 OR MIT class Tests: creation_undo = ( "UNDO Entity creation success", - "UNDO Entity creation failed") + "P0: UNDO Entity creation failed") creation_redo = ( "REDO Entity creation success", - "REDO Entity creation failed") + "P0: REDO Entity creation failed") entity_reference_creation = ( "Entity Reference Entity successfully created", - "Entity Reference Entity failed to be created") + "P0: Entity Reference Entity failed to be created") entity_reference_component = ( "Entity has an Entity Reference component", - "Entity failed to find Entity Reference component") + "P0: Entity failed to find Entity Reference component") enter_game_mode = ( "Entered game mode", - "Failed to enter game mode") + "P0: Failed to enter game mode") exit_game_mode = ( "Exited game mode", - "Couldn't exit game mode") + "P0: Couldn't exit game mode") is_visible = ( "Entity is visible", - "Entity was not visible") + "P0: Entity was not visible") is_hidden = ( "Entity is hidden", - "Entity was not hidden") + "P0: Entity was not hidden") entity_deleted = ( "Entity deleted", - "Entity was not deleted") + "P0: Entity was not deleted") deletion_undo = ( "UNDO deletion success", - "UNDO deletion failed") + "P0: UNDO deletion failed") deletion_redo = ( "REDO deletion success", - "REDO deletion failed") + "P0: REDO deletion failed") + entity_id_references_is_container = ( + "EntityIdReferences is a container property", + "P1: EntityIdReferences is NOT a container property") + container_append = ( + "EntityIdReferences append succeeded", + "P1: EntityIdReferences append did not succeed") + container_add = ( + "EntityIdReferences add succeeded", + "P1: EntityIdReferences add did not succeed") + container_update = ( + "EntityIdReferences update succeeded", + "P1: EntityIdReferences update did not succeed") + container_remove = ( + "EntityIdReferences remove succeeded", + "P1: EntityIdReferences remove did not succeed") + container_reset = ( + "EntityIdReferences reset succeeded", + "P1: EntityIdReferences reset did not succeed") def AtomEditorComponents_EntityReference_AddedToEntity(): @@ -119,6 +137,67 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, entity_reference_entity.exists()) + # Entities for EntityIdReferences tests + test_1 = EditorEntity.create_editor_entity('test_1') + test_2 = EditorEntity.create_editor_entity('test_2') + test_3 = EditorEntity.create_editor_entity('test_3') + + # is container property + Report.result( + Tests.entity_id_references_is_container, + entity_reference_component.is_property_container( + AtomComponentProperties.entity_reference('EntityIdReferences'))) + + # Append entity reference to container + entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + test_1.id) + Report.result( + Tests.container_append, + entity_reference_component.get_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id) + + # Add entity reference to container + entity_reference_component.add_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + 1, test_1.id) + Report.result( + Tests.container_add, + entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) == 2 + ) + + # Update entity reference + entity_reference_component.update_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + 1, test_2.id) + Report.result( + Tests.container_update, + entity_reference_component.get_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id) + + # Remove entity reference + entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + test_3.id) + count_before = entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) + entity_reference_component.remove_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + 1) + count_after = entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) + remove_count = (count_before == 3) and (count_after == 2) + Report.result( + Tests.container_remove, + ((count_before == 3) and (count_after == 2) and + (entity_reference_component.get_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)) + ) + + # Reset + entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences')) + Report.result( + Tests.container_reset, + entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) == 0 + ) + # 5. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) From 05bf066c5afadbfc44d5dfac10bd191e127799d4 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 21 Jan 2022 10:28:22 -0800 Subject: [PATCH 18/36] Removed commented out py code Signed-off-by: Gene Walters --- .../tests/Multiplayer_SimpleNetworkLevelEntity.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py index aadf12d7e3..4548dff0b8 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -61,12 +61,9 @@ def Multiplayer_SimpleNetworkLevelEntity(): ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 1.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this doesn't happen. helper.fail_if_log_line_found('NetworkEntityManager', "RequestNetSpawnableInstantiation: Requested spawnable Root.network.spawnable doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable", section_tracer.errors, ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS) - # 5) Ensure the script graph attached to the level entity is running on both client and server + # 5) Ensure the script graph attached to the level entity is running on the server SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS = 0.25 - # Check Server helper.succeed_if_log_line_found('EditorServer', "Script: SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) - # Check Editor/Client (Uncomment once script asset preload is working properly LYN-9136) - # helper.succeed_if_log_line_found('Script', "SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) # Client # Exit game mode From f93a22cdcc0853df6ebfc77b9c912d438be799b3 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 11:11:39 -0800 Subject: [PATCH 19/36] EntityReference P1 case udpates Signed-off-by: Scott Murray --- ...omEditorComponents_EntityReferenceAdded.py | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index 9dc4869f66..464f2a1892 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -58,6 +58,9 @@ class Tests: container_reset = ( "EntityIdReferences reset succeeded", "P1: EntityIdReferences reset did not succeed") + entity_reference_component_removed = ( + "Entity Reference component removed from entity", + "P1: Entity Reference component NOT removed from entity") def AtomEditorComponents_EntityReference_AddedToEntity(): @@ -78,13 +81,21 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): 2) Add Entity Reference component to Entity Reference 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 Entity Reference entity. - 9) UNDO deletion. - 10) REDO deletion. - 11) Look for errors. + 5) 'EntityIdReferences' is a container property + 6) Append item to 'EntityIdReferences' + 7) Add item to 'EntityIdReferences' + 8) Update item in 'EntityIdReferences' + 9) Remove item from 'EntityIdReferences' + 10) Rest the container property then put one entity reference back for further tests + 11) Remove component + 12) Undo component remove + 13) Enter/Exit game mode. + 14) Test IsHidden. + 15) Test IsVisible. + 16) Delete Entity Reference entity. + 17) UNDO deletion. + 18) REDO deletion. + 19) Look for errors. :return: None """ @@ -142,13 +153,13 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): test_2 = EditorEntity.create_editor_entity('test_2') test_3 = EditorEntity.create_editor_entity('test_3') - # is container property + # 5. 'EntityIdReferences' is a container property Report.result( Tests.entity_id_references_is_container, entity_reference_component.is_property_container( AtomComponentProperties.entity_reference('EntityIdReferences'))) - # Append entity reference to container + # 6. Append item to 'EntityIdReferences' entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id) Report.result( @@ -156,7 +167,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id) - # Add entity reference to container + # 7. Add item to 'EntityIdReferences' entity_reference_component.add_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_1.id) Report.result( @@ -165,7 +176,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): AtomComponentProperties.entity_reference('EntityIdReferences')) == 2 ) - # Update entity reference + # 8. Update item in 'EntityIdReferences' entity_reference_component.update_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_2.id) Report.result( @@ -173,7 +184,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id) - # Remove entity reference + # 9. Remove item from 'EntityIdReferences' entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), test_3.id) count_before = entity_reference_component.get_container_count( @@ -190,41 +201,57 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)) ) - # Reset + # 10. Rest the container property then put one entity reference back for further tests entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences')) + general.idle_wait_frames(1) Report.result( Tests.container_reset, entity_reference_component.get_container_count( - AtomComponentProperties.entity_reference('EntityIdReferences')) == 0 - ) + AtomComponentProperties.entity_reference('EntityIdReferences')) == 0) + entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + test_1.id) - # 5. Enter/Exit game mode. + # 11. Remove component + entity_reference_entity.remove_component(AtomComponentProperties.entity_reference()) + general.idle_wait_frames(1) + Report.result(Tests.entity_reference_component_removed, not entity_reference_entity.has_component( + AtomComponentProperties.entity_reference())) + + # 12. Undo component remove + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.entity_reference_component, entity_reference_entity.has_component( + AtomComponentProperties.entity_reference())) + + # 13. 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. + # 14. Test IsHidden. entity_reference_entity.set_visibility_state(False) Report.result(Tests.is_hidden, entity_reference_entity.is_hidden() is True) - # 7. Test IsVisible. + # 15. Test IsVisible. entity_reference_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, entity_reference_entity.is_visible() is True) - # 8. Delete Entity Reference entity. + # 16. Delete Entity Reference entity. entity_reference_entity.delete() Report.result(Tests.entity_deleted, not entity_reference_entity.exists()) - # 9. UNDO deletion. + # 17. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, entity_reference_entity.exists()) - # 10. REDO deletion. + # 18. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not entity_reference_entity.exists()) - # 11. Look for errors and asserts. + # 19. 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}") From ea3cf928b03bf499bcb9543cfebc54060ac31194 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 21 Jan 2022 14:40:12 -0800 Subject: [PATCH 20/36] Small change looking for logs so py code doesnt need to wait as long Signed-off-by: Gene Walters --- .../Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py index 4548dff0b8..0d1067269c 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -58,7 +58,7 @@ def Multiplayer_SimpleNetworkLevelEntity(): Report.critical_result(TestSuccessFailTuples.find_network_player, player_id.IsValid()) # 4) Check the editor logs for network spawnable errors - ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 1.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this doesn't happen. + ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 0.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this didn't happen. helper.fail_if_log_line_found('NetworkEntityManager', "RequestNetSpawnableInstantiation: Requested spawnable Root.network.spawnable doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable", section_tracer.errors, ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS) # 5) Ensure the script graph attached to the level entity is running on the server From 529c342ecac86479b08ce6b14cbb10ff46d2ba43 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 14:53:11 -0800 Subject: [PATCH 21/36] fixing remove_components Signed-off-by: Scott Murray --- .../editor_python_test_tools/editor_entity_utils.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index c3398406ab..f19bf540a9 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -473,12 +473,11 @@ class EditorEntity: :param component_names: List of component names to remove :return: None """ - type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.GAME) - for type_id in type_ids: - remove_outcome = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", self.id, [type_id]) - assert ( - remove_outcome.IsSuccess() - ), f"Failure: could not remove component from '{self.get_name()}'" + component_ids = [component.id for component in self.get_components_of_type(component_names)] + remove_success = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", component_ids) + assert ( + remove_success + ), f"Failure: could not remove component from '{self.get_name()}'" def get_components_of_type(self, component_names: list) -> List[EditorComponent]: """ From 44cbc7659fd172d7e4f98ad9c8dda54f35ccc761 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 15:00:36 -0800 Subject: [PATCH 22/36] removing unused line Signed-off-by: Scott Murray --- .../tests/hydra_AtomEditorComponents_EntityReferenceAdded.py | 1 - 1 file changed, 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index 464f2a1892..7f15702199 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -193,7 +193,6 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): 1) count_after = entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) - remove_count = (count_before == 3) and (count_after == 2) Report.result( Tests.container_remove, ((count_before == 3) and (count_after == 2) and From 6481b147fc8136a889fefc4c60838c2f6a6d42f5 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 16:03:39 -0800 Subject: [PATCH 23/36] style and other fixes Signed-off-by: Scott Murray --- ...omEditorComponents_EntityReferenceAdded.py | 38 +++++++++---------- .../editor_entity_utils.py | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index 7f15702199..66efab9e01 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -86,9 +86,9 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): 7) Add item to 'EntityIdReferences' 8) Update item in 'EntityIdReferences' 9) Remove item from 'EntityIdReferences' - 10) Rest the container property then put one entity reference back for further tests + 10) Reset the container property then put one entity reference back for further tests 11) Remove component - 12) Undo component remove + 12) UNDO component remove 13) Enter/Exit game mode. 14) Test IsHidden. 15) Test IsVisible. @@ -160,55 +160,53 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): AtomComponentProperties.entity_reference('EntityIdReferences'))) # 6. Append item to 'EntityIdReferences' - entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - test_1.id) + entity_reference_component.append_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id) Report.result( Tests.container_append, entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id) # 7. Add item to 'EntityIdReferences' - entity_reference_component.add_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - 1, test_1.id) + entity_reference_component.add_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_1.id) Report.result( Tests.container_add, entity_reference_component.get_container_count( - AtomComponentProperties.entity_reference('EntityIdReferences')) == 2 - ) + AtomComponentProperties.entity_reference('EntityIdReferences')) == 2) # 8. Update item in 'EntityIdReferences' - entity_reference_component.update_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - 1, test_2.id) + entity_reference_component.update_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_2.id) Report.result( Tests.container_update, entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id) # 9. Remove item from 'EntityIdReferences' - entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - test_3.id) + entity_reference_component.append_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), test_3.id) count_before = entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) - entity_reference_component.remove_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - 1) + entity_reference_component.remove_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) count_after = entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) Report.result( Tests.container_remove, ((count_before == 3) and (count_after == 2) and (entity_reference_component.get_container_item( - AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)) - ) + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id))) - # 10. Rest the container property then put one entity reference back for further tests + # 10. Reset the container property then put one entity reference back for further tests entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences')) general.idle_wait_frames(1) Report.result( Tests.container_reset, entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) == 0) - entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - test_1.id) + entity_reference_component.append_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id) # 11. Remove component entity_reference_entity.remove_component(AtomComponentProperties.entity_reference()) @@ -216,7 +214,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): Report.result(Tests.entity_reference_component_removed, not entity_reference_entity.has_component( AtomComponentProperties.entity_reference())) - # 12. Undo component remove + # 12. UNDO component remove general.undo() general.idle_wait_frames(1) Report.result(Tests.entity_reference_component, entity_reference_entity.has_component( diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index f19bf540a9..d8d4a77a65 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -477,7 +477,7 @@ class EditorEntity: remove_success = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", component_ids) assert ( remove_success - ), f"Failure: could not remove component from '{self.get_name()}'" + ), f"Failure: could not remove component from entity '{self.get_name()}'" def get_components_of_type(self, component_names: list) -> List[EditorComponent]: """ From b83fc89c7440104527f84e66be6965c8b86d1cc6 Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Mon, 24 Jan 2022 15:03:27 -0800 Subject: [PATCH 24/36] Making requested changes to LevelLoadTest Signed-off-by: Neil Widmaier --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 4 ++ .../Atom/atom_utils/atom_constants.py | 2 + .../Atom/tests/hydra_Atom_LevelLoadTest.py | 45 +++++++------------ 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index cca20bbf8c..8fc9838b52 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -23,6 +23,10 @@ class TestAutomation(EditorTestSuite): enable_prefab_system = True + @pytest.mark.test_case_id("C36529679") + class AtomLevelLoadTest_Editor(EditorSharedTest): + from Atom.tests import hydra_Atom_LevelLoadTest as test_module + @pytest.mark.test_case_id("C36525657") class AtomEditorComponents_BloomAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_BloomAdded 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 e6d6ac7fb1..393d71f0b2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -32,6 +32,8 @@ GLOBAL_ILLUMINATION_QUALITY = { 'High': 2, } +# Level list used in Editor Level Load Test +LEVEL_LIST = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest", "Sponza"] class AtomComponentProperties: """ diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py index 77886e2123..1efcbe4d01 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py @@ -23,10 +23,9 @@ def Atom_LevelLoadTest(): 1) Create tuple with level load success and failure messages 2) Open the level using the python test tools command 3) Verify level is loaded using a separate command, and report success/failure - 4) Create tuple with success and failure messages for entering gameplay - 5) Enter gameplay and report result - 6) Create tuple with success and failure messages for exiting gameplay - 7) Exit Gameplay and report result + 4) Enter gameplay and report result using a tuple + 5) Exit Gameplay and report result using a tuple + 6) Look for errors or asserts. :return: None """ @@ -34,45 +33,33 @@ def Atom_LevelLoadTest(): import azlmbr.legacy.general as general from editor_python_test_tools.utils import Report, Tracer, TestHelper - - level_list = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest", "Sponza"] + from Atom.atom_utils.atom_constants import LEVEL_LIST with Tracer() as error_tracer: - # - for level in level_list: + for level in LEVEL_LIST: # 1. Create tuple with level load success and failure messages - level_check_tupple = (f"loaded {level}", f"failed to load {level}") + level_check_tuple = (f"loaded {level}", f"failed to load {level}") # 2. Open the level using the python test tools command TestHelper.init_idle() - TestHelper.open_level("graphics", level) + TestHelper.open_level("Graphics", level) # 3. Verify level is loaded using a separate command, and report success/failure - load_success = general.get_current_level_name() - Report.info(load_success) - if load_success == level: - level_match = True - else: - level_match = False - Report.info(level_match) - Report.result(level_check_tupple, level_match) + Report.result(level_check_tuple, level == general.get_current_level_name()) - # 4. Create tuple with success and failure messages for entering gameplay - Enter_game_mode_tupple = (f"{level} entered gameplay successfully ", f"{level} failed to enter gameplay") + # 4. Enter gameplay and report result using a tuple + enter_game_mode_tuple = (f"{level} entered gameplay successfully ", f"{level} failed to enter gameplay") + TestHelper.enter_game_mode(enter_game_mode_tuple) + general.idle_wait_frames(1) - # 5. Enter gameplay and report result - TestHelper.enter_game_mode(Enter_game_mode_tupple) - - # 6. Create tuple with success and failure messages for exiting gameplay - Exit_game_mode_tupple = (f"{level} exited gameplay successfully ", f"{level} failed to exit gameplay") - - # 7. Exit Gameplay and report result - TestHelper.exit_game_mode(Exit_game_mode_tupple) + # 5. Exit gameplay and report result using a tuple + exit_game_mode_tuple = (f"{level} exited gameplay successfully ", f"{level} failed to exit gameplay") + TestHelper.exit_game_mode(exit_game_mode_tuple) - # 11. Look for errors or asserts. + # 6. 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}") From 191db77e4de274ce812ea261b84c321527567b9d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 24 Jan 2022 22:17:01 -0600 Subject: [PATCH 25/36] Atom Tools: Moved performance monitor system component from ME to ATF Moved the performance monitor system component and metrics gathering from the material editor into atom tools framework so it can be reused and extended by other applications. Replaced the custom performance monitor docked window in the material editor with status bar widgets that are always visible and take up no screen real estate. This could possibly be moved to the base application class or rendered on top of the viewport. Signed-off-by: Guthrie Adams --- .../PerformanceMonitor}/PerformanceMetrics.h | 7 +- .../PerformanceMonitorRequestBus.h | 13 +- .../Code/Source/AtomToolsFrameworkModule.cpp | 3 + .../PerformanceMonitorSystemComponent.cpp} | 99 +++++++------ .../PerformanceMonitorSystemComponent.h} | 29 ++-- .../Code/atomtoolsframework_files.cmake | 4 + .../Viewport/MaterialViewportModule.cpp | 11 +- .../Viewport/MaterialViewportWidget.cpp | 3 - .../Source/Window/MaterialEditorWindow.cpp | 46 +++++- .../Code/Source/Window/MaterialEditorWindow.h | 10 +- .../PerformanceMonitorWidget.cpp | 57 -------- .../PerformanceMonitorWidget.h | 44 ------ .../PerformanceMonitorWidget.ui | 133 ------------------ .../Code/materialeditor_files.cmake | 7 - 14 files changed, 136 insertions(+), 330 deletions(-) rename Gems/Atom/Tools/{MaterialEditor/Code/Source/Viewport => AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor}/PerformanceMetrics.h (82%) rename Gems/Atom/Tools/{MaterialEditor/Code/Source/Viewport => AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor}/PerformanceMonitorRequestBus.h (76%) rename Gems/Atom/Tools/{MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp => AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.cpp} (66%) rename Gems/Atom/Tools/{MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.h => AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.h} (64%) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMetrics.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor/PerformanceMetrics.h similarity index 82% rename from Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMetrics.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor/PerformanceMetrics.h index 12c5bc01d6..57d02d991c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMetrics.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor/PerformanceMetrics.h @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include @@ -12,9 +13,9 @@ #include #include -namespace MaterialEditor +namespace AtomToolsFramework { - //! Data structure containing performance metrics for Material Editor + //! Data structure containing performance metrics struct PerformanceMetrics final { AZ_CLASS_ALLOCATOR(PerformanceMetrics, AZ::SystemAllocator, 0); @@ -22,4 +23,4 @@ namespace MaterialEditor double m_cpuFrameTimeMs = 0; double m_gpuFrameTimeMs = 0; }; -} // namespace MaterialEditor +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor/PerformanceMonitorRequestBus.h similarity index 76% rename from Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorRequestBus.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor/PerformanceMonitorRequestBus.h index 6001787d99..80cdf37a73 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/PerformanceMonitor/PerformanceMonitorRequestBus.h @@ -5,16 +5,16 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include -#include +#include -namespace MaterialEditor +namespace AtomToolsFramework { //! Provides communication with Performance Monitor - class PerformanceMonitorRequests - : public AZ::EBusTraits + class PerformanceMonitorRequests : public AZ::EBusTraits { public: static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; @@ -23,11 +23,10 @@ namespace MaterialEditor //! Enable or disable CPU and GPU monitoring //! @param enabled whether performance monitoring should be enabled virtual void SetProfilerEnabled(bool enabled) = 0; - //! Gather performance metrics for the current frame - virtual void GatherMetrics() = 0; + //! Get current metrics virtual const PerformanceMetrics& GetMetrics() = 0; }; using PerformanceMonitorRequestBus = AZ::EBus; -} // namespace MaterialEditor +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp index 865f12d904..978ac52cca 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace AtomToolsFramework @@ -20,6 +21,7 @@ namespace AtomToolsFramework AtomToolsFrameworkSystemComponent::CreateDescriptor(), AtomToolsDocumentSystemComponent::CreateDescriptor(), AtomToolsMainWindowSystemComponent::CreateDescriptor(), + PerformanceMonitorSystemComponent::CreateDescriptor(), PreviewRendererSystemComponent::CreateDescriptor(), }); } @@ -30,6 +32,7 @@ namespace AtomToolsFramework azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), + azrtti_typeid(), azrtti_typeid(), }; } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.cpp similarity index 66% rename from Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.cpp index c8f12480b5..b1cca6c1ab 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.cpp @@ -6,74 +6,44 @@ * */ -#include - #include #include #include +#include +#include -#include - -namespace MaterialEditor +namespace AtomToolsFramework { - void PerformanceMonitorComponent::Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0); - } - } - - PerformanceMonitorComponent::PerformanceMonitorComponent() - { - } - - void PerformanceMonitorComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) + void PerformanceMonitorSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { provided.push_back(AZ_CRC_CE("PerformanceMonitorService")); } - void PerformanceMonitorComponent::Init() + void PerformanceMonitorSystemComponent::Reflect(AZ::ReflectContext* context) + { + if (AZ::SerializeContext* serialize = azrtti_cast(context)) + { + serialize->Class()->Version(0); + } + } + + void PerformanceMonitorSystemComponent::Init() { } - void PerformanceMonitorComponent::Activate() + void PerformanceMonitorSystemComponent::Activate() { + AZ::TickBus::Handler::BusConnect(); PerformanceMonitorRequestBus::Handler::BusConnect(); } - void PerformanceMonitorComponent::Deactivate() + void PerformanceMonitorSystemComponent::Deactivate() { PerformanceMonitorRequestBus::Handler::BusDisconnect(); + AZ::TickBus::Handler::BusDisconnect(); } - void PerformanceMonitorComponent::SetProfilerEnabled(bool enabled) - { - if (m_profilingEnabled == enabled) - { - return; - } - - AZ::RHI::Ptr rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass(); - if (rootPass) - { - rootPass->SetTimestampQueryEnabled(enabled); - } - else - { - AZ_Error("PerformanceMonitorComponent", false, "Failed to find root pass."); - } - - if (enabled) - { - ResetStats(); - } - - m_profilingEnabled = enabled; - } - - void PerformanceMonitorComponent::GatherMetrics() + void PerformanceMonitorSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) { if (!m_profilingEnabled) { @@ -103,21 +73,46 @@ namespace MaterialEditor } } - const PerformanceMetrics& PerformanceMonitorComponent::GetMetrics() + void PerformanceMonitorSystemComponent::SetProfilerEnabled(bool enabled) + { + if (m_profilingEnabled == enabled) + { + return; + } + + AZ::RHI::Ptr rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass(); + if (rootPass) + { + rootPass->SetTimestampQueryEnabled(enabled); + } + else + { + AZ_Error("PerformanceMonitorSystemComponent", false, "Failed to find root pass."); + } + + if (enabled) + { + ResetStats(); + } + + m_profilingEnabled = enabled; + } + + const PerformanceMetrics& PerformanceMonitorSystemComponent::GetMetrics() { UpdateMetrics(); return m_metrics; } - void PerformanceMonitorComponent::UpdateMetrics() + void PerformanceMonitorSystemComponent::UpdateMetrics() { m_metrics.m_cpuFrameTimeMs = m_cpuFrameTimeMs.GetAverage(); m_metrics.m_gpuFrameTimeMs = m_gpuFrameTimeMs.GetAverage(); } - void PerformanceMonitorComponent::ResetStats() + void PerformanceMonitorSystemComponent::ResetStats() { m_cpuFrameTimeMs.Reset(); m_gpuFrameTimeMs.Reset(); } -} +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.h similarity index 64% rename from Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.h index 3045bf9533..2cc336f07c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/PerformanceMonitorComponent.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/PerformanceMonitor/PerformanceMonitorSystemComponent.h @@ -10,25 +10,26 @@ #include #include +#include #include -#include +#include -namespace MaterialEditor +namespace AtomToolsFramework { - //! PerformanceMonitorComponent monitors performance within Material Editor - class PerformanceMonitorComponent + //! PerformanceMonitorSystemComponent monitors performance + class PerformanceMonitorSystemComponent : public AZ::Component , private PerformanceMonitorRequestBus::Handler + , private AZ::TickBus::Handler { public: - AZ_COMPONENT(PerformanceMonitorComponent, "{C2F54D1B-A106-4922-82BE-ACB7A168D4AF}"); - - static void Reflect(AZ::ReflectContext* context); - - PerformanceMonitorComponent(); - ~PerformanceMonitorComponent() = default; + AZ_COMPONENT(PerformanceMonitorSystemComponent, "{C2F54D1B-A106-4922-82BE-ACB7A168D4AF}"); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); + static void Reflect(AZ::ReflectContext* context); + + PerformanceMonitorSystemComponent() = default; + ~PerformanceMonitorSystemComponent() = default; private: // AZ::Component overrides... @@ -36,9 +37,11 @@ namespace MaterialEditor void Activate() override; void Deactivate() override; - // PerformanceMonitorRequestBus::Handler interface overrides... + // AZ::TickBus::Handler overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + // PerformanceMonitorRequestBus::Handler overrides... void SetProfilerEnabled(bool enabled) override; - void GatherMetrics() override; const PerformanceMetrics& GetMetrics() override; void UpdateMetrics(); @@ -55,4 +58,4 @@ namespace MaterialEditor static constexpr int SampleCount = 10; int m_sample = 0; }; -} +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index db20452036..1dbfb7b686 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -28,6 +28,8 @@ set(FILES Include/AtomToolsFramework/Inspector/InspectorGroupWidget.h Include/AtomToolsFramework/Inspector/InspectorGroupHeaderWidget.h Include/AtomToolsFramework/Inspector/InspectorPropertyGroupWidget.h + Include/AtomToolsFramework/PerformanceMonitor/PerformanceMetrics.h + Include/AtomToolsFramework/PerformanceMonitor/PerformanceMonitorRequestBus.h Include/AtomToolsFramework/Util/MaterialPropertyUtil.h Include/AtomToolsFramework/Util/Util.h Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -61,6 +63,8 @@ set(FILES Source/Inspector/InspectorGroupWidget.cpp Source/Inspector/InspectorGroupHeaderWidget.cpp Source/Inspector/InspectorPropertyGroupWidget.cpp + Source/PerformanceMonitor/PerformanceMonitorSystemComponent.cpp + Source/PerformanceMonitor/PerformanceMonitorSystemComponent.h Source/Util/MaterialPropertyUtil.cpp Source/Util/Util.cpp Source/Viewport/RenderViewportWidget.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportModule.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportModule.cpp index 01a13519fb..5467a2607c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportModule.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportModule.cpp @@ -8,16 +8,16 @@ #include #include -#include namespace MaterialEditor { MaterialViewportModule::MaterialViewportModule() { // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. - m_descriptors.insert(m_descriptors.end(), { - MaterialViewportComponent::CreateDescriptor(), - PerformanceMonitorComponent::CreateDescriptor(), + m_descriptors.insert( + m_descriptors.end(), + { + MaterialViewportComponent::CreateDescriptor(), }); } @@ -25,7 +25,6 @@ namespace MaterialEditor { return AZ::ComponentTypeList{ azrtti_typeid(), - azrtti_typeid(), }; } -} +} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp index dd157c59ac..21b01b5dab 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp @@ -50,7 +50,6 @@ #include #include #include -#include #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT @@ -462,8 +461,6 @@ namespace MaterialEditor m_renderPipeline->AddToRenderTickOnce(); - PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics); - if (m_shadowCatcherMaterial) { // Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame. diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index d538f62e15..49356e6735 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include @@ -30,6 +30,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include +#include #include #include AZ_POP_DISABLE_WARNING @@ -95,10 +96,7 @@ namespace MaterialEditor AddDockWidget("Inspector", new MaterialInspector, Qt::RightDockWidgetArea, Qt::Vertical); AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Vertical); - AddDockWidget("Performance Monitor", new PerformanceMonitorWidget, Qt::BottomDockWidgetArea, Qt::Horizontal); - SetDockWidgetVisible("Viewport Settings", false); - SetDockWidgetVisible("Performance Monitor", false); // Restore geometry and show the window mainWindowWrapper->showFromSettings(); @@ -114,6 +112,14 @@ namespace MaterialEditor } OnDocumentOpened(AZ::Uuid::CreateNull()); + + SetupMetrics(); + } + + MaterialEditorWindow::~MaterialEditorWindow() + { + AtomToolsFramework::PerformanceMonitorRequestBus::Broadcast( + &AtomToolsFramework::PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, false); } void MaterialEditorWindow::ResizeViewportRenderTarget(uint32_t width, uint32_t height) @@ -207,6 +213,38 @@ namespace MaterialEditor Base::closeEvent(closeEvent); } + + void MaterialEditorWindow::SetupMetrics() + { + m_statusBarCpuTime = new QLabel(this); + statusBar()->addPermanentWidget(m_statusBarCpuTime); + m_statusBarGpuTime = new QLabel(this); + statusBar()->addPermanentWidget(m_statusBarGpuTime); + m_statusBarFps = new QLabel(this); + statusBar()->addPermanentWidget(m_statusBarFps); + + static constexpr int UpdateIntervalMs = 1000; + m_metricsTimer.setInterval(UpdateIntervalMs); + m_metricsTimer.start(); + connect(&m_metricsTimer, &QTimer::timeout, this, &MaterialEditorWindow::UpdateMetrics); + + AtomToolsFramework::PerformanceMonitorRequestBus::Broadcast( + &AtomToolsFramework::PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, true); + + UpdateMetrics(); + } + + void MaterialEditorWindow::UpdateMetrics() + { + AtomToolsFramework::PerformanceMetrics metrics = {}; + AtomToolsFramework::PerformanceMonitorRequestBus::BroadcastResult( + metrics, &AtomToolsFramework::PerformanceMonitorRequestBus::Handler::GetMetrics); + + m_statusBarCpuTime->setText(tr("CPU Time %1 ms").arg(QString::number(metrics.m_cpuFrameTimeMs, 'f', 2))); + m_statusBarGpuTime->setText(tr("GPU Time %1 ms").arg(QString::number(metrics.m_gpuFrameTimeMs, 'f', 2))); + int frameRate = metrics.m_cpuFrameTimeMs > 0 ? aznumeric_cast(1000 / metrics.m_cpuFrameTimeMs) : 0; + m_statusBarFps->setText(tr("FPS %1").arg(QString::number(frameRate))); + } } // namespace MaterialEditor #include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h index 8317382d6d..3cf08e0374 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h @@ -14,6 +14,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include #include +#include AZ_POP_DISABLE_WARNING #endif @@ -33,7 +34,7 @@ namespace MaterialEditor using Base = AtomToolsFramework::AtomToolsDocumentMainWindow; MaterialEditorWindow(QWidget* parent = 0); - ~MaterialEditorWindow() = default; + ~MaterialEditorWindow(); protected: void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override; @@ -48,7 +49,14 @@ namespace MaterialEditor void closeEvent(QCloseEvent* closeEvent) override; + void SetupMetrics(); + void UpdateMetrics(); + MaterialViewportWidget* m_materialViewport = {}; MaterialEditorToolBar* m_toolBar = {}; + QLabel* m_statusBarFps = {}; + QLabel* m_statusBarCpuTime = {}; + QLabel* m_statusBarGpuTime = {}; + QTimer m_metricsTimer; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp deleted file mode 100644 index 8492ce5f1f..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp +++ /dev/null @@ -1,57 +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 - * - */ - -#include -#include -#include - -#include - -namespace MaterialEditor -{ - PerformanceMonitorWidget::PerformanceMonitorWidget(QWidget* parent) - : QWidget(parent) - , m_ui(new Ui::PerformanceMonitorWidget) - { - m_ui->setupUi(this); - - - m_updateTimer.setInterval(UpdateIntervalMs); - connect(&m_updateTimer, &QTimer::timeout, this, &PerformanceMonitorWidget::UpdateMetrics); - } - - PerformanceMonitorWidget::~PerformanceMonitorWidget() = default; - - void PerformanceMonitorWidget::showEvent(QShowEvent* event) - { - QWidget::showEvent(event); - - m_updateTimer.start(); - PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, true); - } - - void PerformanceMonitorWidget::hideEvent(QHideEvent* event) - { - QWidget::hideEvent(event); - - m_updateTimer.stop(); - PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, false); - } - - void PerformanceMonitorWidget::UpdateMetrics() - { - PerformanceMetrics metrics; - PerformanceMonitorRequestBus::BroadcastResult(metrics, &PerformanceMonitorRequestBus::Handler::GetMetrics); - m_ui->m_cpuFrameTimeValue->setText(QString("%1 ms").arg(QString::number(metrics.m_cpuFrameTimeMs, 'f', 2))); - m_ui->m_gpuFrameTimeValue->setText(QString("%1 ms").arg(QString::number(metrics.m_gpuFrameTimeMs, 'f', 2))); - int frameRate = metrics.m_cpuFrameTimeMs > 0 ? aznumeric_cast(1000 / metrics.m_cpuFrameTimeMs) : 0; - m_ui->m_frameRateValue->setText(QString::number(frameRate)); - } -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h deleted file mode 100644 index 1570d61aa3..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h +++ /dev/null @@ -1,44 +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 - -namespace Ui -{ - class PerformanceMonitorWidget; -} - -namespace MaterialEditor -{ - //! Displays performance metrics for Material Editor - class PerformanceMonitorWidget - : public QWidget - { - Q_OBJECT - public: - PerformanceMonitorWidget(QWidget* parent = nullptr); - ~PerformanceMonitorWidget(); - - private slots: - void UpdateMetrics(); - - private: - void showEvent(QShowEvent* event) override; - void hideEvent(QHideEvent* event) override; - - QScopedPointer m_ui; - QTimer m_updateTimer; - - - //! interval to request performance metrics - static constexpr int UpdateIntervalMs = 1000; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui deleted file mode 100644 index 776ce79a87..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui +++ /dev/null @@ -1,133 +0,0 @@ - - - PerformanceMonitorWidget - - - - 0 - 0 - 237 - 200 - - - - - 200 - 200 - - - - Performance Monitor - - - - - - - - Frame Rate: - - - - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - CPU Frame Time: - - - - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - GPU Frame Time: - - - - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 67 - - - - - - - - - diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index f062246413..4e270460a6 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -23,8 +23,6 @@ set(FILES Source/Viewport/MaterialViewportSettings.h Source/Viewport/MaterialViewportRequestBus.h Source/Viewport/MaterialViewportNotificationBus.h - Source/Viewport/PerformanceMetrics.h - Source/Viewport/PerformanceMonitorRequestBus.h Source/Viewport/InputController/MaterialEditorViewportInputController.cpp Source/Viewport/InputController/MaterialEditorViewportInputController.h Source/Viewport/InputController/Behavior.cpp @@ -49,8 +47,6 @@ set(FILES Source/Viewport/MaterialViewportWidget.cpp Source/Viewport/MaterialViewportWidget.h Source/Viewport/MaterialViewportWidget.ui - Source/Viewport/PerformanceMonitorComponent.cpp - Source/Viewport/PerformanceMonitorComponent.h Source/Window/MaterialEditorWindowSettings.h Source/Window/MaterialEditorBrowserInteractions.h @@ -67,9 +63,6 @@ set(FILES Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp Source/Window/CreateMaterialDialog/CreateMaterialDialog.h Source/Window/CreateMaterialDialog/CreateMaterialDialog.ui - Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp - Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h - Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui Source/Window/ToolBar/MaterialEditorToolBar.h Source/Window/ToolBar/MaterialEditorToolBar.cpp Source/Window/ToolBar/ModelPresetComboBox.h From a3cb6b8c5b59af17f2cbeacd3d23fa07ff326f7a Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:58:07 -0600 Subject: [PATCH 26/36] AP: Update Sqlite to version 3.37.2 (#7124) * Update sqlite package for windows Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add assert to make sure sqlite header and lib version match Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update linux Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Update Builting Package / Mac for Sqlite 3.37.2-rev1 Signed-off-by: spham <82231385+spham-amzn@users.noreply.github.com> * Re-add newline at end of file Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Co-authored-by: spham <82231385+spham-amzn@users.noreply.github.com> --- .../AzToolsFramework/SQLite/SQLiteConnection.cpp | 3 +++ cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/SQLite/SQLiteConnection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/SQLite/SQLiteConnection.cpp index e262c77529..9e2a458d97 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/SQLite/SQLiteConnection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/SQLite/SQLiteConnection.cpp @@ -65,6 +65,9 @@ namespace AzToolsFramework bool Connection::Open(const AZStd::string& filename, bool readOnly) { + AZ_Assert(sqlite3_libversion_number() == SQLITE_VERSION_NUMBER, "Sqlite header version number does not match library"); + AZ_Assert(strncmp(sqlite3_sourceid(), SQLITE_SOURCE_ID, 80) == 0, "Sqlite header source id does not match library"); + AZ_Assert(strcmp(sqlite3_libversion(), SQLITE_VERSION) == 0, "Sqlite header version does not match library"); AZ_Assert(m_db == NULL, "You have to close the database prior to opening a new one."); if (m_db) { diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index ee91415a6d..5dce95dc77 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -45,4 +45,4 @@ ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev2-linux ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-linux TARGETS ISPCTexComp PACKAGE_HASH 065fd12abe4247dde247330313763cf816c3375c221da030bdec35024947f259) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-linux TARGETS lz4 PACKAGE_HASH 5de3dbd3e2a3537c6555d759b3c5bb98e5456cf85c74ff6d046f809b7087290d) ly_associate_package(PACKAGE_NAME pyside2-5.15.2-rev2-linux TARGETS pyside2 PACKAGE_HASH 7589c397c8224d0c3ad691ff02e1afd55d9a1f9de1967c14eb8105dd2b0c4dd1) -ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev1-linux TARGETS SQLite PACKAGE_HASH a8e167591f7f5f060a2e5718d2fcabb80436544421180d475a075624b5ced4c5) +ly_associate_package(PACKAGE_NAME SQLite-3.37.2-rev1-linux TARGETS SQLite PACKAGE_HASH bee80d6c6db3e312c1f4f089c90894436ea9c9b74d67256d8c1fb00d4d81fe46) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 1bcad01c1d..5087ac2669 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -15,7 +15,6 @@ ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-mac TARGETS expat PACKAGE_HASH 231ec2cb8ef9ddeef891e5bd7215ad91864e3410a22fad5ab8355e7bf53621fe) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) -ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) @@ -43,3 +42,4 @@ ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev5-mac ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-mac TARGETS ISPCTexComp PACKAGE_HASH 8a4e93277b8face6ea2fd57c6d017bdb55643ed3d6387110bc5f6b3b884dd169) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-mac TARGETS lz4 PACKAGE_HASH 891ff630bf34f7ab1d8eaee2ea0a8f1fca89dbdc63fca41ee592703dd488a73b) ly_associate_package(PACKAGE_NAME azslc-1.7.34-rev1-mac TARGETS azslc PACKAGE_HASH a9d81946b42ffa55c0d14d6a9249b3340e59a8fb8835e7a96c31df80f14723bc) +ly_associate_package(PACKAGE_NAME SQLite-3.37.2-rev1-mac TARGETS SQLite PACKAGE_HASH f9101023f99cf32fc5867284ceb28c0761c23d2c5a4b1748349c69f976a2fbea) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index c872708a3a..fbff29e887 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -15,7 +15,6 @@ ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-windows TARGETS expat PACKAGE_HASH 123d81dcd0e30306fdb0d062348b992e68358cc31f0a15a98c4c04fc68dc437e) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) -ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) @@ -49,3 +48,4 @@ ly_associate_package(PACKAGE_NAME astc-encoder-3.2-rev2-windows ly_associate_package(PACKAGE_NAME ISPCTexComp-36b80aa-rev1-windows TARGETS ISPCTexComp PACKAGE_HASH b6fa6ea28a2808a9a5524c72c37789c525925e435770f2d94eb2d387360fa2d0) ly_associate_package(PACKAGE_NAME lz4-1.9.3-vcpkg-rev4-windows TARGETS lz4 PACKAGE_HASH 4ea457b833cd8cfaf8e8e06ed6df601d3e6783b606bdbc44a677f77e19e0db16) ly_associate_package(PACKAGE_NAME azslc-1.7.34-rev1-windows TARGETS azslc PACKAGE_HASH 44eb2e0fc4b0f1c75d0fb6f24c93a5753655b84dbc3e6ad45389ed3b9cf7a4b0) +ly_associate_package(PACKAGE_NAME SQLite-3.37.2-rev1-windows TARGETS SQLite PACKAGE_HASH c1658c8ed5cf0e45d4a5da940c6a6d770b76e0f4f57313b70d0fd306885f015e) From 956a1e59bbbfaf2808cb45710a24ce86c30e147e Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:58:17 -0600 Subject: [PATCH 27/36] [LYN-9039] Object stream write response change (#7085) * Updated the ObjectStreamWriteOverride Callback to return a ObjectStreamWriteOverrideResponse. The ObjectStreamWriteOverrideResponse allows the callback to indicate that the default ObjectStream::WriteElement behavior should occur if the callback hasn't implemented the write itself. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed forward declaration not matching actual enum class name Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add unit tests Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Remove unused member Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Add virtual destructor for test class Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Change string literal to not have tabs in it Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- .../AzCore/Serialization/ObjectStream.cpp | 18 ++- .../AzCore/Serialization/ObjectStream.h | 14 ++- .../Serialization/std/VariantReflection.inl | 7 +- Code/Framework/AzCore/Tests/Serialization.cpp | 103 ++++++++++++++++++ .../AzFramework/Asset/AssetBundleManifest.cpp | 7 +- 5 files changed, 142 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp index ac44ac150c..6132cf0a56 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.cpp @@ -1668,9 +1668,23 @@ namespace AZ SerializeContext::ENUM_ACCESS_FOR_READ, &m_errorLogger ); - if (objectStreamWriteOverrideCB.Invoke(callContext, objectPtr, *classData, classElement)) + if (ObjectStreamWriteOverrideResponse writeResponse; + objectStreamWriteOverrideCB.Read(writeResponse, callContext, objectPtr, *classData, classElement)) { - return false; + switch (writeResponse) + { + case ObjectStreamWriteOverrideResponse::FallbackToDefaultWrite: + break; + case ObjectStreamWriteOverrideResponse::AbortWrite: + m_errorLogger.ReportError(AZStd::string::format("ObjectStream Write Element Override callback has aborted the write for class data %s", + classData->m_name).c_str()); + [[fallthrough]]; + case ObjectStreamWriteOverrideResponse::CompletedWrite: + return false; + default: + AZ_Error("Serialize", false, "Invalid Response %d returned from the ObjectStream Write Element Override callback", static_cast(writeResponse)); + return false; + } } else { diff --git a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h index 9f9b3fc9f0..1985821c7b 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h +++ b/Code/Framework/AzCore/AzCore/Serialization/ObjectStream.h @@ -49,14 +49,24 @@ namespace AZ static const AZ::Crc32 ObjectStreamWriteElementOverride = AZ_CRC("ObjectStreamWriteElementOverride", 0x35eb659f); } + enum class ObjectStreamWriteOverrideResponse + { + CompletedWrite, + FallbackToDefaultWrite, + AbortWrite + }; + AZ_TYPE_INFO_SPECIALIZE(ObjectStreamWriteOverrideResponse, "{BDF960A8-0F18-4E9D-96DA-F800A122C42D}"); + ///< Callback that the object stream invokes to override saving an instance of the registered class ///< @param callContext EnumerateInstanceCallContext which contains the WriteElement BeingElemCB and the CloseElement EndElemCB ///< the callContext parameter can be passed to the SerializeContext::EnumerateInstance to continue object stream writing ///< @param classPtr class type which is of pointer to the type represented by the m_typeId value ///< @param classData reference to this instance Class Data that will be supplied to the callback ///< @param classElement class element pointer which contains information about the element being serialized. - ///< root elements do not not have a valid class element pointer - using ObjectStreamWriteOverrideCB = AZStd::function; AZ_TYPE_INFO_SPECIALIZE(ObjectStreamWriteOverrideCB, "{87B1A36B-8C8A-42B6-A0B5-E770D9FDBAD4}"); diff --git a/Code/Framework/AzCore/AzCore/Serialization/std/VariantReflection.inl b/Code/Framework/AzCore/AzCore/Serialization/std/VariantReflection.inl index 06d4f76c80..33f9995752 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/std/VariantReflection.inl +++ b/Code/Framework/AzCore/AzCore/Serialization/std/VariantReflection.inl @@ -12,6 +12,8 @@ namespace AZ { + enum class ObjectStreamWriteOverrideResponse; + namespace VariantSerializationInternal { template @@ -480,7 +482,7 @@ namespace AZ } } private: - static void ObjectStreamWriter(SerializeContext::EnumerateInstanceCallContext& callContext, const void* variantPtr, + static ObjectStreamWriteOverrideResponse ObjectStreamWriter(SerializeContext::EnumerateInstanceCallContext& callContext, const void* variantPtr, [[maybe_unused]] const SerializeContext::ClassData& variantClassData, const SerializeContext::ClassElement* variantClassElement) { auto alternativeVisitor = [&callContext, variantClassElement](auto&& elementAlt) @@ -503,6 +505,9 @@ namespace AZ }; AZStd::visit(AZStd::move(alternativeVisitor), *reinterpret_cast(variantPtr)); + // To avoid including ObjectStream.h into this file, we static cast the value of 0 + // to an AZ::ObjectStreamWriteElemntResponse which corresponds to the CompletedWrite enum value + return static_cast(0); } VariantSerializationInternal::AZStdVariantContainer m_variantContainer; diff --git a/Code/Framework/AzCore/Tests/Serialization.cpp b/Code/Framework/AzCore/Tests/Serialization.cpp index bbfafc352f..102fa8b2c8 100644 --- a/Code/Framework/AzCore/Tests/Serialization.cpp +++ b/Code/Framework/AzCore/Tests/Serialization.cpp @@ -720,6 +720,49 @@ namespace SerializeTestClasses { AZStd::intrusive_ptr m_intrusivePtr; AZStd::unique_ptr m_uniquePtr; }; + + struct ElementOverrideType + { + AZ_RTTI(ElementOverrideType, "{BAA18B6C-3CB3-476C-8B41-21EA7CE1F4CF}"); + AZ_CLASS_ALLOCATOR(ElementOverrideType, AZ::SystemAllocator, 0); + + virtual ~ElementOverrideType() = default; + + static AZ::ObjectStreamWriteOverrideResponse Writer( + AZ::SerializeContext::EnumerateInstanceCallContext& callContext, + const void* object, + const AZ::SerializeContext::ClassData&, + const AZ::SerializeContext::ClassElement*) + { + auto ptr = static_cast(object); + + if(ptr) + { + switch(ptr->m_field) + { + case 0: + { + float output{}; + callContext.m_context->EnumerateInstanceConst(&callContext, &output, azrtti_typeid(), nullptr, nullptr); + return AZ::ObjectStreamWriteOverrideResponse::CompletedWrite; + } + case 1: + return AZ::ObjectStreamWriteOverrideResponse::FallbackToDefaultWrite; + } + } + + return AZ::ObjectStreamWriteOverrideResponse::AbortWrite; + } + + static void Reflect(AZ::SerializeContext& sc) + { + sc.Class() + ->Attribute(AZ::SerializeContextAttributes::ObjectStreamWriteElementOverride, &ElementOverrideType::Writer) + ->Field("field", &ElementOverrideType::m_field); + } + + int m_field = 0; + }; } //SerializeTestClasses namespace AZ @@ -1698,6 +1741,66 @@ namespace UnitTest } } + TEST_F(Serialization, ElementOverrideTest_DefaultSerializationWorks) + { + ElementOverrideType::Reflect(*m_serializeContext); + + ElementOverrideType testType; + testType.m_field = 1; // Our custom serializer will use the default output when this value is 1 + + AZStd::vector buffer; + IO::ByteContainerStream> stream(&buffer); + ASSERT_TRUE(Utils::SaveObjectToStream(stream, DataStream::ST_XML, &testType, m_serializeContext.get())); + + constexpr const char* expectedValue = + R"()" "\n" + "\t" R"()" "\n" + "\t\t" R"()" "\n" + "\t" R"()" "\n" + R"()"; + + AZStd::string result(buffer.data(), stream.GetLength()); + AZ::StringFunc::TrimWhiteSpace(result, true, true); + + EXPECT_STREQ(result.c_str(), expectedValue); + } + + TEST_F(Serialization, ElementOverrideTest_CustomSerializationWorks) + { + ElementOverrideType::Reflect(*m_serializeContext); + + ElementOverrideType testType; + testType.m_field = 0; // Our custom serializer will do its own output when this value is 0 + + AZStd::vector buffer; + IO::ByteContainerStream> stream(&buffer); + ASSERT_TRUE(Utils::SaveObjectToStream(stream, DataStream::ST_XML, &testType, m_serializeContext.get())); + + constexpr const char* expectedValue = + R"()" "\n" + "\t" R"()" "\n" + R"()"; + + AZStd::string result(buffer.data(), stream.GetLength()); + AZ::StringFunc::TrimWhiteSpace(result, true, true); + + EXPECT_STREQ(result.c_str(), expectedValue); + } + + TEST_F(Serialization, ElementOverrideTest_FailureCase) + { + ElementOverrideType::Reflect(*m_serializeContext); + + ElementOverrideType testType; + testType.m_field = 2; // Our custom serializer will report a failure when this value is not 0/1 + + AZStd::vector buffer; + IO::ByteContainerStream> stream(&buffer); + AZ_TEST_START_TRACE_SUPPRESSION; + ASSERT_FALSE(Utils::SaveObjectToStream(stream, DataStream::ST_XML, &testType, m_serializeContext.get())); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + TEST_F(Serialization, ContainerTypeContainedTypeDiffersByPointer) { ContainersTest::ReflectVectorOfInts(m_serializeContext.get()); diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.cpp index b4da5745be..0c941fc016 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetBundleManifest.cpp @@ -15,7 +15,7 @@ namespace AzFramework { // Redirects writing of the AssetBundleManifest to an older version if the bundle version // is not set to the current version - static void OldBundleManifestWriter(AZ::SerializeContext::EnumerateInstanceCallContext& callContext, const void* bundleManifestPointer, + static AZ::ObjectStreamWriteOverrideResponse OldBundleManifestWriter(AZ::SerializeContext::EnumerateInstanceCallContext& callContext, const void* bundleManifestPointer, const AZ::SerializeContext::ClassData&, const AZ::SerializeContext::ClassElement* assetBundleManifestClassElement); static bool BundleManifestVersionConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& rootElement); @@ -67,7 +67,7 @@ namespace AzFramework return true; } - void OldBundleManifestWriter(AZ::SerializeContext::EnumerateInstanceCallContext& callContext, const void* bundleManifestPointer, + AZ::ObjectStreamWriteOverrideResponse OldBundleManifestWriter(AZ::SerializeContext::EnumerateInstanceCallContext& callContext, const void* bundleManifestPointer, const AZ::SerializeContext::ClassData&, const AZ::SerializeContext::ClassElement* assetBundleManifestClassElement) { // Copy the AssetBundleManifest current version instance to the AssetBundleManifest V2 instance @@ -145,7 +145,10 @@ namespace AzFramework ReflectAssetBundleManifestV2(serializeContext); serializeContext->DisableRemoveReflection(); AssetBundleManifest::ReflectSerialize(serializeContext); + return AZ::ObjectStreamWriteOverrideResponse::CompletedWrite; } + + return AZ::ObjectStreamWriteOverrideResponse::FallbackToDefaultWrite; } const AZStd::vector& AssetBundleManifest::GetLevelDirectories() const From 55146d037a4626257b80285967c13767221dc896 Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Tue, 25 Jan 2022 11:25:18 -0800 Subject: [PATCH 28/36] Add manipulator for atom render plugin in animation editor. (#7068) * small bugfix Signed-off-by: rhhong * ActorInstanceId default to -1 when no %lastresult matches Signed-off-by: rhhong * CR feedback - wrap function to get the first available editor actor instance. Signed-off-by: rhhong * Remove mcore inline Signed-off-by: rhhong * Fixed the bug that delete an instance from actor manager crashes the editor. Signed-off-by: rhhong * Move the manipulator controller. Signed-off-by: rhhong * Add manipulator icon Signed-off-by: rhhong * Add manipulators Signed-off-by: rhhong * move more option to renderOption, and loading all going through the plugin Signed-off-by: rhhong * code cleanup Signed-off-by: rhhong * code cleanup Signed-off-by: rhhong * more code cleanup Signed-off-by: rhhong * CR FEEDBACK Signed-off-by: rhhong * Fix profile_nounity build Signed-off-by: rhhong * CR feedback - move more code to azToolsframework and share them between animation editor and editorlib Signed-off-by: rhhong * Using the MouseViewportRequests in viewportMessage and remove the custom bus Signed-off-by: rhhong --- Code/Editor/ViewportManipulatorController.cpp | 55 +--- Code/Editor/ViewportManipulatorController.h | 4 - .../Viewport/ViewportInteractionHelpers.cpp | 60 +++++ .../Viewport/ViewportInteractionHelpers.h | 23 ++ .../Viewport/ViewportMessages.h | 3 + .../aztoolsframework_files.cmake | 2 + .../EMotionFXAtom/Assets/Icons/Resources.qrc | 3 + .../EMotionFXAtom/Assets/Icons/Rotate.svg | 10 + .../EMotionFXAtom/Assets/Icons/Scale.svg | 11 + .../EMotionFXAtom/Assets/Icons/Translate.svg | 15 ++ .../EMStudio/AnimViewportInputController.cpp | 141 ++++++++++ .../EMStudio/AnimViewportInputController.h | 36 +++ .../Tools/EMStudio/AnimViewportRenderer.cpp | 14 + .../Tools/EMStudio/AnimViewportRenderer.h | 3 +- .../Tools/EMStudio/AnimViewportRequestBus.h | 28 +- .../Tools/EMStudio/AnimViewportToolBar.cpp | 104 +++++--- .../Code/Tools/EMStudio/AnimViewportToolBar.h | 10 +- .../Tools/EMStudio/AnimViewportWidget.cpp | 75 ++---- .../Code/Tools/EMStudio/AnimViewportWidget.h | 13 +- .../Code/Tools/EMStudio/AtomRenderPlugin.cpp | 242 +++++++++++++++++- .../Code/Tools/EMStudio/AtomRenderPlugin.h | 28 +- .../Code/emotionfx_atom_editor_files.cmake | 2 + .../Source/RenderPlugin/RenderOptions.cpp | 61 +++++ .../Source/RenderPlugin/RenderOptions.h | 47 +++- .../Source/RenderPlugin/RenderPlugin.cpp | 6 +- .../Source/RenderPlugin/RenderViewWidget.cpp | 2 - 26 files changed, 790 insertions(+), 208 deletions(-) create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp create mode 100644 Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp create mode 100644 Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h diff --git a/Code/Editor/ViewportManipulatorController.cpp b/Code/Editor/ViewportManipulatorController.cpp index 9879a84b62..93c999f71f 100644 --- a/Code/Editor/ViewportManipulatorController.cpp +++ b/Code/Editor/ViewportManipulatorController.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -33,53 +34,6 @@ namespace SandboxEditor ViewportManipulatorControllerInstance::~ViewportManipulatorControllerInstance() = default; - AzToolsFramework::ViewportInteraction::MouseButton ViewportManipulatorControllerInstance::GetMouseButton( - const AzFramework::InputChannel& inputChannel) - { - using AzToolsFramework::ViewportInteraction::MouseButton; - using InputButton = AzFramework::InputDeviceMouse::Button; - const auto& id = inputChannel.GetInputChannelId(); - if (id == InputButton::Left) - { - return MouseButton::Left; - } - if (id == InputButton::Middle) - { - return MouseButton::Middle; - } - if (id == InputButton::Right) - { - return MouseButton::Right; - } - return MouseButton::None; - } - - bool ViewportManipulatorControllerInstance::IsMouseMove(const AzFramework::InputChannel& inputChannel) - { - return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition; - } - - AzToolsFramework::ViewportInteraction::KeyboardModifier ViewportManipulatorControllerInstance::GetKeyboardModifier( - const AzFramework::InputChannel& inputChannel) - { - using AzToolsFramework::ViewportInteraction::KeyboardModifier; - using Key = AzFramework::InputDeviceKeyboard::Key; - const auto& id = inputChannel.GetInputChannelId(); - if (id == Key::ModifierAltL || id == Key::ModifierAltR) - { - return KeyboardModifier::Alt; - } - if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR) - { - return KeyboardModifier::Ctrl; - } - if (id == Key::ModifierShiftL || id == Key::ModifierShiftR) - { - return KeyboardModifier::Shift; - } - return KeyboardModifier::None; - } - bool ViewportManipulatorControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) { // We only care about manipulator and viewport interaction events @@ -97,6 +51,7 @@ namespace SandboxEditor using AzToolsFramework::ViewportInteraction::MouseInteractionEvent; using AzToolsFramework::ViewportInteraction::ProjectedViewportRay; using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus; + using AzToolsFramework::ViewportInteraction::Helpers; bool interactionHandled = false; float wheelDelta = 0.0f; @@ -109,7 +64,7 @@ namespace SandboxEditor const bool finishedProcessingEvents = event.m_priority == InteractionPriority; const auto state = event.m_inputChannel.GetState(); - if (IsMouseMove(event.m_inputChannel)) + if (Helpers::IsMouseMove(event.m_inputChannel)) { // Cache the ray trace results when doing manipulator interaction checks, no need to recalculate after if (event.m_priority == ManipulatorPriority) @@ -136,7 +91,7 @@ namespace SandboxEditor eventType = MouseEvent::Move; } - else if (auto mouseButton = GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None) + else if (auto mouseButton = Helpers::GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None) { const AZ::u32 mouseButtonValue = static_cast(mouseButton); overrideButton = mouseButton; @@ -178,7 +133,7 @@ namespace SandboxEditor } } } - else if (auto keyboardModifier = GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None) + else if (auto keyboardModifier = Helpers::GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None) { if (state == InputChannel::State::Began || state == InputChannel::State::Updated) { diff --git a/Code/Editor/ViewportManipulatorController.h b/Code/Editor/ViewportManipulatorController.h index b9c359a544..4872d32fd6 100644 --- a/Code/Editor/ViewportManipulatorController.h +++ b/Code/Editor/ViewportManipulatorController.h @@ -35,10 +35,6 @@ namespace SandboxEditor private: bool IsDoubleClick(AzToolsFramework::ViewportInteraction::MouseButton) const; - static AzToolsFramework::ViewportInteraction::MouseButton GetMouseButton(const AzFramework::InputChannel& inputChannel); - static bool IsMouseMove(const AzFramework::InputChannel& inputChannel); - static AzToolsFramework::ViewportInteraction::KeyboardModifier GetKeyboardModifier(const AzFramework::InputChannel& inputChannel); - //! Represents the time and location of a click. struct ClickEvent { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp new file mode 100644 index 0000000000..6cf74f2a11 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.cpp @@ -0,0 +1,60 @@ +/* + * 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 AzToolsFramework::ViewportInteraction +{ + MouseButton Helpers::GetMouseButton(const AzFramework::InputChannel& inputChannel) + { + using AzToolsFramework::ViewportInteraction::MouseButton; + using InputButton = AzFramework::InputDeviceMouse::Button; + const AzFramework::InputChannelId& id = inputChannel.GetInputChannelId(); + if (id == InputButton::Left) + { + return MouseButton::Left; + } + if (id == InputButton::Middle) + { + return MouseButton::Middle; + } + if (id == InputButton::Right) + { + return MouseButton::Right; + } + return MouseButton::None; + } + + bool Helpers::IsMouseMove(const AzFramework::InputChannel& inputChannel) + { + return inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::SystemCursorPosition; + } + + KeyboardModifier Helpers::GetKeyboardModifier(const AzFramework::InputChannel& inputChannel) + { + using AzToolsFramework::ViewportInteraction::KeyboardModifier; + using Key = AzFramework::InputDeviceKeyboard::Key; + const auto& id = inputChannel.GetInputChannelId(); + if (id == Key::ModifierAltL || id == Key::ModifierAltR) + { + return KeyboardModifier::Alt; + } + if (id == Key::ModifierCtrlL || id == Key::ModifierCtrlR) + { + return KeyboardModifier::Ctrl; + } + if (id == Key::ModifierShiftL || id == Key::ModifierShiftR) + { + return KeyboardModifier::Shift; + } + return KeyboardModifier::None; + } +} // namespace AzToolsFramework::ViewportInteraction diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h new file mode 100644 index 0000000000..65edf1eaef --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportInteractionHelpers.h @@ -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 + * + */ +#pragma once + +#include +#include + + +namespace AzToolsFramework::ViewportInteraction +{ + class Helpers + { + public: + static MouseButton GetMouseButton(const AzFramework::InputChannel& inputChannel); + static bool IsMouseMove(const AzFramework::InputChannel& inputChannel); + static KeyboardModifier GetKeyboardModifier(const AzFramework::InputChannel& inputChannel); + }; +} // namespace AzToolsFramework::ViewportInteraction diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 4dbcc9d926..3426be7dcf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -150,6 +150,9 @@ namespace AzToolsFramework static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; }; + //! A bus to listen to just the MouseViewportRequests. + using ViewportMouseRequestBus = AZ::EBus; + //! Requests that can be made to the viewport to query and modify its state. class ViewportInteractionRequests { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index 0d7bf05211..98b0c5644d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -504,6 +504,8 @@ set(FILES Viewport/EditorContextMenu.cpp Viewport/VertexContainerDisplay.h Viewport/VertexContainerDisplay.cpp + Viewport/ViewportInteractionHelpers.h + Viewport/ViewportInteractionHelpers.cpp Viewport/ViewportMessages.h Viewport/ViewportMessages.cpp Viewport/ViewportTypes.h diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc index 7924ef1c4e..d035b84479 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Resources.qrc @@ -1,6 +1,9 @@ Camera_category.svg + Rotate.svg + Scale.svg + Translate.svg Visualization.svg diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg new file mode 100644 index 0000000000..97da939a86 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Rotate.svg @@ -0,0 +1,10 @@ + + + + Icons / System / Rotate + Created with Sketch. + + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg new file mode 100644 index 0000000000..6375650a52 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Scale.svg @@ -0,0 +1,11 @@ + + + + Icons / System / Scale + Created with Sketch. + + + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg new file mode 100644 index 0000000000..51d107de98 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Assets/Icons/Translate.svg @@ -0,0 +1,15 @@ + + + + Icons / System / Move + Created with Sketch. + + + + + + + + + + diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp new file mode 100644 index 0000000000..f229dbd0b5 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.cpp @@ -0,0 +1,141 @@ +/* + * 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 + + +namespace EMStudio +{ + bool AnimViewportInputController::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) + { + using AzFramework::InputChannel; + using AzToolsFramework::ViewportInteraction::KeyboardModifier; + using AzToolsFramework::ViewportInteraction::MouseButton; + using AzToolsFramework::ViewportInteraction::MouseEvent; + using AzToolsFramework::ViewportInteraction::MouseInteraction; + using AzToolsFramework::ViewportInteraction::MouseInteractionEvent; + using AzToolsFramework::ViewportInteraction::ProjectedViewportRay; + using AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus; + using AzToolsFramework::ViewportInteraction::Helpers; + + bool interactionHandled = false; + float wheelDelta = 0.0f; + AZStd::optional overrideButton; + AZStd::optional eventType; + + const auto state = event.m_inputChannel.GetState(); + if (Helpers::IsMouseMove(event.m_inputChannel)) + { + const auto* position = event.m_inputChannel.GetCustomData(); + AZ_Assert(position, "Expected PositionData2D but found nullptr"); + + AzFramework::WindowSize windowSize; + AzFramework::WindowRequestBus::EventResult( + windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize); + + const auto screenPoint = AzFramework::ScreenPoint( + aznumeric_cast(position->m_normalizedPosition.GetX() * windowSize.m_width), + aznumeric_cast(position->m_normalizedPosition.GetY() * windowSize.m_height)); + + ProjectedViewportRay ray{}; + ViewportInteractionRequestBus::EventResult( + ray, GetViewportId(), &ViewportInteractionRequestBus::Events::ViewportScreenToWorldRay, screenPoint); + + m_mouseInteraction.m_mousePick.m_rayOrigin = ray.m_origin; + m_mouseInteraction.m_mousePick.m_rayDirection = ray.m_direction; + m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint; + + eventType = MouseEvent::Move; + } + else if (auto mouseButton = Helpers::GetMouseButton(event.m_inputChannel); mouseButton != MouseButton::None) + { + const AZ::u32 mouseButtonValue = static_cast(mouseButton); + overrideButton = mouseButton; + if (state == InputChannel::State::Began) + { + m_mouseInteraction.m_mouseButtons.m_mouseButtons |= mouseButtonValue; + eventType = MouseEvent::Down; + } + else if (state == InputChannel::State::Ended) + { + // If we've actually logged a mouse down event, forward a mouse up event. + // This prevents corner cases like the context menu thinking it should be opened even though no one clicked in this + // viewport, due to RenderViewportWidget ensuring all controllers get InputChannel::State::Ended events. + if (m_mouseInteraction.m_mouseButtons.m_mouseButtons & mouseButtonValue) + { + eventType = MouseEvent::Up; + } + } + } + else if (auto keyboardModifier = Helpers::GetKeyboardModifier(event.m_inputChannel); keyboardModifier != KeyboardModifier::None) + { + if (state == InputChannel::State::Began || state == InputChannel::State::Updated) + { + m_mouseInteraction.m_keyboardModifiers.m_keyModifiers |= static_cast(keyboardModifier); + } + else if (state == InputChannel::State::Ended) + { + m_mouseInteraction.m_keyboardModifiers.m_keyModifiers &= ~static_cast(keyboardModifier); + } + } + else if (event.m_inputChannel.GetInputChannelId() == AzFramework::InputDeviceMouse::Movement::Z) + { + if (state == InputChannel::State::Began || state == InputChannel::State::Updated) + { + eventType = MouseEvent::Wheel; + wheelDelta = event.m_inputChannel.GetValue(); + } + } + + if (eventType) + { + MouseInteraction mouseInteraction = m_mouseInteraction; + if (overrideButton) + { + mouseInteraction.m_mouseButtons.m_mouseButtons = static_cast(overrideButton.value()); + } + + mouseInteraction.m_interactionId.m_viewportId = GetViewportId(); + + auto currentCursorState = AzFramework::SystemCursorState::Unknown; + AzFramework::InputSystemCursorRequestBus::EventResult( + currentCursorState, event.m_inputChannel.GetInputDevice().GetInputDeviceId(), + &AzFramework::InputSystemCursorRequestBus::Events::GetSystemCursorState); + + const auto mouseInteractionEvent = [mouseInteraction, event = eventType.value(), wheelDelta, + cursorCaptured = currentCursorState == AzFramework::SystemCursorState::ConstrainedAndHidden] + { + switch (event) + { + case MouseEvent::Up: + case MouseEvent::Down: + case MouseEvent::Move: + case MouseEvent::DoubleClick: + return MouseInteractionEvent(AZStd::move(mouseInteraction), event, cursorCaptured); + case MouseEvent::Wheel: + return MouseInteractionEvent(AZStd::move(mouseInteraction), wheelDelta); + } + + AZ_Assert(false, "Unhandled MouseEvent"); + return MouseInteractionEvent(MouseInteraction{}, MouseEvent::Up, false); + }(); + + AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::EventResult(interactionHandled, + GetViewportId(), &AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::HandleMouseInteraction, + mouseInteractionEvent); + } + + return interactionHandled; + } +} // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h new file mode 100644 index 0000000000..d6b6771178 --- /dev/null +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportInputController.h @@ -0,0 +1,36 @@ +/* + * 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 +{ + class ManipulatorManager; +} + +namespace EMStudio +{ + //! Provide input control for manipulators in AnimViewport + class AnimViewportInputController + : public AzFramework::SingleViewportController + { + public: + AZ_TYPE_INFO(AnimViewportInputController, "{A1629CB6-2292-4B7D-8B49-F614BD4746AA}"); + AZ_CLASS_ALLOCATOR(AnimViewportInputController, AZ::SystemAllocator, 0) + + // AzFramework::SingleViewportController overrides... + bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; + + private: + + AzToolsFramework::ViewportInteraction::MouseInteraction m_mouseInteraction; + }; +} // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp index 5e4afb68c7..6ac2a66261 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.cpp @@ -210,6 +210,20 @@ namespace EMStudio return m_frameworkScene; } + AZ::EntityId AnimViewportRenderer::GetEntityId() const + { + if (m_actorEntities.empty()) + { + return AZ::EntityId(); + } + return m_actorEntities[0]->GetId(); + } + + AzFramework::EntityContextId AnimViewportRenderer::GetEntityContextId() const + { + return m_entityContext->GetContextId(); + } + 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 10745c6c26..0066c222db 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRenderer.h @@ -55,8 +55,9 @@ namespace EMStudio AZ::Vector3 GetCharacterCenter() const; void UpdateActorRenderFlag(EMotionFX::ActorRenderFlagBitset renderFlags); - AZStd::shared_ptr GetFrameworkScene() const; + AZ::EntityId GetEntityId() const; + AzFramework::EntityContextId GetEntityContextId() const; private: diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h index 9a0bee1fec..9b2fc0b212 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportRequestBus.h @@ -8,21 +8,10 @@ #pragma once #include -#include +#include namespace EMStudio { - enum CameraViewMode - { - FRONT, - BACK, - TOP, - BOTTOM, - LEFT, - RIGHT, - DEFAULT - }; - class AnimViewportRequests : public AZ::EBusTraits { @@ -30,17 +19,14 @@ namespace EMStudio static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - //! Reset the camera to initial state. - virtual void ResetCamera() = 0; + //! Update the camera view mode. + virtual void UpdateCameraViewMode(EMStudio::RenderOptions::CameraViewMode mode) = 0; - //! Set the camera view mode. - virtual void SetCameraViewMode(CameraViewMode mode) = 0; + //! Update the camera follow up option + virtual void UpdateCameraFollowUp(bool followUp) = 0; - //! Set the camera follow up - virtual void SetFollowCharacter(bool follow) = 0; - - //! Toggle render option flag - virtual void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) = 0; + //! Update render flags + virtual void UpdateRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) = 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 962c9417b7..455c587818 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.cpp @@ -7,21 +7,48 @@ */ #include +#include #include #include +#include #include #include #include #include #include + namespace EMStudio { - AnimViewportToolBar::AnimViewportToolBar(QWidget* parent) + AnimViewportToolBar::AnimViewportToolBar(AtomRenderPlugin* plugin, QWidget* parent) : QToolBar(parent) + , m_plugin(plugin) { AzQtComponents::ToolBar::addMainToolBarStyle(this); + // Add the manipulator actions + QActionGroup* manipulatorGroup = new QActionGroup(this); + manipulatorGroup->setExclusive(true); + manipulatorGroup->setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional); + m_manipulatorActions[RenderOptions::TRANSLATE] = addAction(QIcon(":/EMotionFXAtom/Translate.svg"), "Translate"); + m_manipulatorActions[RenderOptions::ROTATE] = addAction(QIcon(":/EMotionFXAtom/Rotate.svg"), "Rotate"); + m_manipulatorActions[RenderOptions::SCALE] = addAction(QIcon(":/EMotionFXAtom/Scale.svg"), "Scale"); + for (size_t i = RenderOptions::ManipulatorMode::TRANSLATE; i < RenderOptions::ManipulatorMode::NUM_MODES; ++i) + { + m_manipulatorActions[i]->setCheckable(true); + connect( + m_manipulatorActions[i], &QAction::triggered, this, + [this, i]() + { + const RenderOptions::ManipulatorMode mode = + m_manipulatorActions[i]->isChecked() ? RenderOptions::ManipulatorMode(i) : RenderOptions::ManipulatorMode::SELECT; + m_plugin->GetRenderOptions()->SetManipulatorMode(mode); + m_plugin->SetManipulatorMode(mode); + }); + manipulatorGroup->addAction(m_manipulatorActions[i]); + } + addSeparator(); + // Add the render view options button QToolButton* renderOptionsButton = new QToolButton(this); { @@ -66,30 +93,35 @@ namespace EMStudio 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" }, + const AZStd::vector> cameraOptionNames = { + { RenderOptions::CameraViewMode::FRONT, "Front" }, + { RenderOptions::CameraViewMode::BACK, "Back" }, + { RenderOptions::CameraViewMode::TOP, "Top" }, + { RenderOptions::CameraViewMode::BOTTOM, "Bottom" }, + { RenderOptions::CameraViewMode::LEFT, "Left" }, + { RenderOptions::CameraViewMode::RIGHT, "Right" }, }; for (const auto& pair : cameraOptionNames) { - CameraViewMode mode = pair.first; + RenderOptions::CameraViewMode mode = pair.first; cameraMenu->addAction( pair.second.c_str(), - [mode]() + [this, mode]() { - // Send the reset camera event. - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::SetCameraViewMode, mode); + m_plugin->GetRenderOptions()->SetCameraViewMode(mode); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateCameraViewMode, mode); }); } cameraMenu->addSeparator(); cameraMenu->addAction( "Reset Camera", - []() + [this]() { - // Send the reset camera event. - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::ResetCamera); + m_plugin->GetRenderOptions()->SetCameraViewMode(RenderOptions::CameraViewMode::DEFAULT); + AnimViewportRequestBus::Broadcast( + &AnimViewportRequestBus::Events::UpdateCameraViewMode, RenderOptions::CameraViewMode::DEFAULT); }); cameraMenu->addSeparator(); @@ -99,8 +131,9 @@ namespace EMStudio connect(m_followCharacterAction, &QAction::triggered, this, [this]() { + m_plugin->GetRenderOptions()->SetCameraFollowUp(m_followCharacterAction->isChecked()); AnimViewportRequestBus::Broadcast( - &AnimViewportRequestBus::Events::SetFollowCharacter, m_followCharacterAction->isChecked()); + &AnimViewportRequestBus::Events::UpdateCameraFollowUp, m_followCharacterAction->isChecked()); ; }); @@ -117,7 +150,6 @@ namespace EMStudio AnimViewportToolBar::~AnimViewportToolBar() { - SaveSettings(); } void AnimViewportToolBar::CreateViewOptionEntry( @@ -125,11 +157,11 @@ namespace EMStudio { QAction* action = menu->addAction( menuEntryName, - [actionIndex]() + [this, actionIndex]() { + m_plugin->GetRenderOptions()->ToggerRenderFlag(actionIndex); // Send the reset camera event. - AnimViewportRequestBus::Broadcast( - &AnimViewportRequestBus::Events::ToggleRenderFlag, (EMotionFX::ActorRenderFlag)actionIndex); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateRenderFlags, m_plugin->GetRenderOptions()->GetRenderFlags()); }); action->setCheckable(true); action->setVisible(visible); @@ -139,38 +171,32 @@ namespace EMStudio action->setIcon(QIcon(iconFileName)); } - m_actions[actionIndex] = action; + m_renderActions[actionIndex] = action; } - void AnimViewportToolBar::SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) + void AnimViewportToolBar::LoadSettings() { + const RenderOptions* renderOptions = m_plugin->GetRenderOptions(); + + const bool isChecked = renderOptions->GetCameraFollowUp(); + m_followCharacterAction->setChecked(isChecked); + AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::UpdateCameraFollowUp, isChecked); + + RenderOptions::ManipulatorMode mode = renderOptions->GetManipulatorMode(); + m_plugin->SetManipulatorMode(mode); + if (mode != RenderOptions::ManipulatorMode::SELECT) + { + m_manipulatorActions[mode]->setChecked(true); + } + + const EMotionFX::ActorRenderFlagBitset renderFlags = renderOptions->GetRenderFlags(); for (size_t i = 0; i < renderFlags.size(); ++i) { - QAction* action = m_actions[i]; + QAction* action = m_renderActions[i]; if (action) { action->setChecked(renderFlags[i]); } } } - - void AnimViewportToolBar::LoadSettings() - { - AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); - renderFlagsFilename += "AnimViewportRenderFlags.cfg"; - QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); - - const bool isChecked = settings.value("CameraFollowUp", false).toBool(); - m_followCharacterAction->setChecked(isChecked); - AnimViewportRequestBus::Broadcast(&AnimViewportRequestBus::Events::SetFollowCharacter, isChecked); - } - - void AnimViewportToolBar::SaveSettings() - { - AZStd::string renderFlagsFilename(EMStudioManager::GetInstance()->GetAppDataFolder()); - renderFlagsFilename += "AnimViewportRenderFlags.cfg"; - QSettings settings(renderFlagsFilename.c_str(), QSettings::IniFormat, this); - - settings.setValue("CameraFollowUp", m_followCharacterAction->isChecked()); - } } // namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h index 98b07f07dd..30f2c6b80c 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportToolBar.h @@ -18,21 +18,23 @@ namespace EMStudio { + class AnimRenderPlugin; + class AnimViewportToolBar : public QToolBar { public: - AnimViewportToolBar(QWidget* parent = nullptr); + AnimViewportToolBar(AtomRenderPlugin* plugin, QWidget* parent); ~AnimViewportToolBar(); - void SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); void LoadSettings(); - void SaveSettings(); 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 }; + AtomRenderPlugin* m_plugin = nullptr; + QAction* m_manipulatorActions[RenderOptions::ManipulatorMode::NUM_MODES] = { nullptr }; + QAction* m_renderActions[EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS] = { nullptr }; QAction* m_followCharacterAction = nullptr; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp index ae70b5bd43..90fbb81e47 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.cpp @@ -37,7 +37,6 @@ namespace EMStudio m_renderer = AZStd::make_unique(GetViewportContext(), m_plugin->GetRenderOptions()); SetScene(m_renderer->GetFrameworkScene(), false); - LoadRenderFlags(); SetupCameras(); SetupCameraController(); Reinit(); @@ -48,7 +47,6 @@ namespace EMStudio AnimViewportWidget::~AnimViewportWidget() { - SaveRenderFlags(); ViewportPluginRequestBus::Handler::BusDisconnect(); AnimViewportRequestBus::Handler::BusDisconnect(); } @@ -56,19 +54,14 @@ namespace EMStudio void AnimViewportWidget::Reinit(bool resetCamera) { m_renderer->Reinit(); - m_renderer->UpdateActorRenderFlag(m_renderFlags); + m_renderer->UpdateActorRenderFlag(m_plugin->GetRenderOptions()->GetRenderFlags()); if (resetCamera) { - ResetCamera(); + UpdateCameraViewMode(RenderOptions::CameraViewMode::DEFAULT); } } - EMotionFX::ActorRenderFlagBitset AnimViewportWidget::GetRenderFlags() const - { - return m_renderFlags; - } - void AnimViewportWidget::SetupCameras() { m_rotateCamera = AZStd::make_shared(EMStudio::ViewportUtil::BuildRotateCameraInputId()); @@ -134,37 +127,32 @@ namespace EMStudio GetControllerList()->Add(controller); } - void AnimViewportWidget::ResetCamera() - { - SetCameraViewMode(CameraViewMode::DEFAULT); - } - - void AnimViewportWidget::SetCameraViewMode(CameraViewMode mode) + void AnimViewportWidget::UpdateCameraViewMode(RenderOptions::CameraViewMode mode) { // Set the camera view mode. const AZ::Vector3 targetPosition = m_renderer->GetCharacterCenter(); AZ::Vector3 cameraPosition; switch (mode) { - case CameraViewMode::FRONT: + case RenderOptions::CameraViewMode::FRONT: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() + CameraDistance, targetPosition.GetZ()); break; - case CameraViewMode::BACK: + case RenderOptions::CameraViewMode::BACK: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY() - CameraDistance, targetPosition.GetZ()); break; - case CameraViewMode::TOP: + case RenderOptions::CameraViewMode::TOP: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), CameraDistance + targetPosition.GetZ()); break; - case CameraViewMode::BOTTOM: + case RenderOptions::CameraViewMode::BOTTOM: cameraPosition.Set(targetPosition.GetX(), targetPosition.GetY(), -CameraDistance + targetPosition.GetZ()); break; - case CameraViewMode::LEFT: + case RenderOptions::CameraViewMode::LEFT: cameraPosition.Set(targetPosition.GetX() - CameraDistance, targetPosition.GetY(), targetPosition.GetZ()); break; - case CameraViewMode::RIGHT: + case RenderOptions::CameraViewMode::RIGHT: cameraPosition.Set(targetPosition.GetX() + CameraDistance, targetPosition.GetY(), targetPosition.GetZ()); break; - case CameraViewMode::DEFAULT: + case RenderOptions::CameraViewMode::DEFAULT: // The default view mode is looking from the top left of the character. cameraPosition.Set( targetPosition.GetX() - CameraDistance, targetPosition.GetY() + CameraDistance, targetPosition.GetZ() + CameraDistance); @@ -178,9 +166,9 @@ namespace EMStudio AZ::Vector3::CreateAxisY(-CameraDistance)); } - void AnimViewportWidget::SetFollowCharacter(bool follow) + void AnimViewportWidget::UpdateCameraFollowUp(bool followUp) { - if (follow) + if (followUp) { AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraOffset, @@ -195,8 +183,6 @@ namespace EMStudio GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached, GetViewportContext()->GetCameraTransform().GetTranslation()); } - - m_followCharacter = follow; } void AnimViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time) @@ -229,13 +215,13 @@ namespace EMStudio for (size_t i = 0; i < numPlugins; ++i) { EMStudioPlugin* plugin = GetPluginManager()->GetActivePlugin(i); - plugin->Render(m_renderFlags); + plugin->Render(m_plugin->GetRenderOptions()->GetRenderFlags()); } } void AnimViewportWidget::FollowCharacter() { - if (m_followCharacter) + if (m_plugin->GetRenderOptions()->GetCameraFollowUp()) { AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( GetViewportId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotAttached, @@ -243,38 +229,9 @@ namespace EMStudio } } - void AnimViewportWidget::ToggleRenderFlag(EMotionFX::ActorRenderFlag flag) + void AnimViewportWidget::UpdateRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) { - 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]); - } + m_renderer->UpdateActorRenderFlag(renderFlags); } AZ::s32 AnimViewportWidget::GetViewportId() const diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h index 528cf61d09..9e4a7c5fa7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AnimViewportWidget.h @@ -31,7 +31,6 @@ namespace EMStudio AnimViewportRenderer* GetAnimViewportRenderer() { return m_renderer.get(); } void Reinit(bool resetCamera = true); - EMotionFX::ActorRenderFlagBitset GetRenderFlags() const; private: void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; @@ -43,14 +42,10 @@ namespace EMStudio void SetupCameras(); void SetupCameraController(); - void LoadRenderFlags(); - void SaveRenderFlags(); - // AnimViewportRequestBus::Handler overrides - void ResetCamera(); - void SetCameraViewMode(CameraViewMode mode); - void SetFollowCharacter(bool follow); - void ToggleRenderFlag(EMotionFX::ActorRenderFlag flag); + void UpdateCameraViewMode(RenderOptions::CameraViewMode mode); + void UpdateCameraFollowUp(bool follow); + void UpdateRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); // ViewportPluginRequestBus::Handler overrides AZ::s32 GetViewportId() const; @@ -62,7 +57,5 @@ namespace EMStudio AZStd::shared_ptr m_rotateCamera; AZStd::shared_ptr m_translateCamera; AZStd::shared_ptr m_orbitDollyScrollCamera; - EMotionFX::ActorRenderFlagBitset m_renderFlags; - bool m_followCharacter = false; }; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp index 297bfea760..660f8e52d7 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.cpp @@ -6,31 +6,49 @@ * */ +#include +#include +#include +#include +#include + #include #include #include +#include #include #include #include #include #include +#include + namespace EMStudio { AZ_CLASS_ALLOCATOR_IMPL(AtomRenderPlugin, EMotionFX::EditorAllocator, 0); + const AzToolsFramework::ManipulatorManagerId g_animManipulatorManagerId = + AzToolsFramework::ManipulatorManagerId(AZ::Crc32("AnimManipulatorManagerId")); AtomRenderPlugin::AtomRenderPlugin() : DockWidgetPlugin() + , m_translationManipulators( + AzToolsFramework::TranslationManipulators::Dimensions::Three, AZ::Transform::Identity(), AZ::Vector3::CreateOne()) + , m_rotateManipulators(AZ::Transform::CreateIdentity()) + , m_scaleManipulators(AZ::Transform::CreateIdentity()) { } AtomRenderPlugin::~AtomRenderPlugin() { + SaveRenderOptions(); GetCommandManager()->RemoveCommandCallback(m_importActorCallback, false); GetCommandManager()->RemoveCommandCallback(m_removeActorCallback, false); delete m_importActorCallback; delete m_removeActorCallback; + + AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::BusDisconnect(); } const char* AtomRenderPlugin::GetName() const @@ -86,6 +104,7 @@ namespace EMStudio void AtomRenderPlugin::ReinitRenderer() { m_animViewportWidget->Reinit(); + SetManipulatorMode(m_renderOptions.GetManipulatorMode()); } bool AtomRenderPlugin::Init() @@ -104,21 +123,171 @@ namespace EMStudio m_animViewportWidget = new AnimViewportWidget(this); // Add the tool bar - AnimViewportToolBar* toolBar = new AnimViewportToolBar(m_innerWidget); - toolBar->SetRenderFlags(m_animViewportWidget->GetRenderFlags()); + AnimViewportToolBar* toolBar = new AnimViewportToolBar(this, m_innerWidget); verticalLayout->addWidget(toolBar); verticalLayout->addWidget(m_animViewportWidget); + m_manipulatorManager = AZStd::make_shared(g_animManipulatorManagerId); + SetupManipulators(); + // Register command callbacks. m_importActorCallback = new ImportActorCallback(false); m_removeActorCallback = new RemoveActorCallback(false); EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("ImportActor", m_importActorCallback); EMStudioManager::GetInstance()->GetCommandManager()->RegisterCommandCallback("RemoveActor", m_removeActorCallback); + AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler::BusConnect( + m_animViewportWidget->GetViewportContext()->GetId()); + return true; } + void AtomRenderPlugin::SetupManipulators() + { + // Add the manipulator controller + m_animViewportWidget->GetControllerList()->Add(AZStd::make_shared()); + + // Gather information about the entity + AZ::Transform worldTransform = AZ::Transform::CreateIdentity(); + worldTransform.SetTranslation(m_animViewportWidget->GetAnimViewportRenderer()->GetCharacterCenter()); + + // Setup the translation manipulator + m_translationManipulators.SetSpace(worldTransform); + AzToolsFramework::ConfigureTranslationManipulatorAppearance3d(&m_translationManipulators); + m_translationManipulators.InstallLinearManipulatorMouseMoveCallback( + [this](const AzToolsFramework::LinearManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition()); + }); + + m_translationManipulators.InstallPlanarManipulatorMouseMoveCallback( + [this](const AzToolsFramework::PlanarManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition()); + }); + + m_translationManipulators.InstallSurfaceManipulatorMouseMoveCallback( + [this](const AzToolsFramework::SurfaceManipulator::Action& action) + { + OnManipulatorMoved(action.LocalPosition()); + }); + + // Setup the rotation manipulator + m_rotateManipulators.SetSpace(worldTransform); + m_rotateManipulators.SetLocalAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + m_rotateManipulators.ConfigureView( + AzToolsFramework::RotationManipulatorRadius(), AzFramework::ViewportColors::XAxisColor, AzFramework::ViewportColors::YAxisColor, + AzFramework::ViewportColors::ZAxisColor); + m_rotateManipulators.InstallMouseMoveCallback( + [this](const AzToolsFramework::AngularManipulator::Action& action) + { + OnManipulatorRotated(action.LocalOrientation()); + }); + + // Setup the scale manipulator + m_scaleManipulators.SetSpace(worldTransform); + m_scaleManipulators.SetAxes(AZ::Vector3::CreateAxisX(), AZ::Vector3::CreateAxisY(), AZ::Vector3::CreateAxisZ()); + m_scaleManipulators.ConfigureView( + AzToolsFramework::LinearManipulatorAxisLength(), AzFramework::ViewportColors::XAxisColor, + AzFramework::ViewportColors::YAxisColor, AzFramework::ViewportColors::ZAxisColor); + m_scaleManipulators.InstallAxisMouseMoveCallback( + [this](const AzToolsFramework::LinearManipulator::Action& action) + { + OnManipulatorScaled(action.LocalScale(), action.LocalScaleOffset()); + }); + } + + void AtomRenderPlugin::SetManipulatorMode(RenderOptions::ManipulatorMode mode) + { + if (!m_manipulatorManager) + { + return; + } + + if (mode == RenderOptions::ManipulatorMode::SELECT) + { + m_translationManipulators.Unregister(); + m_rotateManipulators.Unregister(); + m_scaleManipulators.Unregister(); + return; + } + + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + if (!entityId.IsValid()) + { + return; + } + + AZ::Vector3 localPos; + AZ::TransformBus::EventResult(localPos, entityId, &AZ::TransformBus::Events::GetLocalTranslation); + + switch (mode) + { + case RenderOptions::ManipulatorMode::SELECT: + // The AtomRenderPlugin doesn't implement a select mode + break; + case RenderOptions::ManipulatorMode::TRANSLATE: + { + m_translationManipulators.Register(g_animManipulatorManagerId); + m_translationManipulators.SetLocalPosition(localPos); + m_rotateManipulators.Unregister(); + m_scaleManipulators.Unregister(); + } + break; + case RenderOptions::ManipulatorMode::ROTATE: + { + m_translationManipulators.Unregister(); + m_rotateManipulators.Register(g_animManipulatorManagerId); + m_rotateManipulators.SetLocalPosition(localPos); + m_scaleManipulators.Unregister(); + } + break; + case RenderOptions::ManipulatorMode::SCALE: + { + m_translationManipulators.Unregister(); + m_rotateManipulators.Unregister(); + m_scaleManipulators.Register(g_animManipulatorManagerId); + m_scaleManipulators.SetLocalPosition(localPos); + } + break; + } + } + + void AtomRenderPlugin::OnManipulatorMoved(const AZ::Vector3& position) + { + m_translationManipulators.SetLocalPosition(position); + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalTranslation, position); + } + + void AtomRenderPlugin::OnManipulatorRotated(const AZ::Quaternion& rotation) + { + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalRotationQuaternion, rotation); + } + + void AtomRenderPlugin::OnManipulatorScaled( + const AZ::Vector3& scale, const AZ::Vector3& scaleOffset) + { + // Use the scaleOffset to determine which axis to use on the uniform scale. + float localScale = 1.0f; + if (scaleOffset.GetX() != 0.0f) + { + localScale = scale.GetX(); + } + else if (scaleOffset.GetY() != 0.0f) + { + localScale = scale.GetY(); + } + else if (scaleOffset.GetZ() != 0.0f) + { + localScale = scale.GetZ(); + } + const AZ::EntityId entityId = m_animViewportWidget->GetAnimViewportRenderer()->GetEntityId(); + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, localScale); + } + void AtomRenderPlugin::LoadRenderOptions() { AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder()); @@ -127,11 +296,78 @@ namespace EMStudio m_renderOptions = RenderOptions::Load(&settings); } - const RenderOptions* AtomRenderPlugin::GetRenderOptions() const + void AtomRenderPlugin::SaveRenderOptions() + { + AZStd::string renderOptionsFilename(GetManager()->GetAppDataFolder()); + renderOptionsFilename += "EMStudioRenderOptions.cfg"; + QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this); + m_renderOptions.Save(&settings); + } + + RenderOptions* AtomRenderPlugin::GetRenderOptions() { return &m_renderOptions; } + void AtomRenderPlugin::Render([[maybe_unused]]EMotionFX::ActorRenderFlagBitset renderFlags) + { + if (!m_animViewportWidget) + { + return; + } + + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, m_animViewportWidget->GetViewportContext()->GetId()); + AzFramework::DebugDisplayRequests* debugDisplay = AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + + namespace AztfVi = AzToolsFramework::ViewportInteraction; + AztfVi::KeyboardModifiers keyboardModifiers; + AztfVi::EditorModifierKeyRequestBus::BroadcastResult( + keyboardModifiers, &AztfVi::EditorModifierKeyRequestBus::Events::QueryKeyboardModifiers); + + debugDisplay->DepthTestOff(); + const AzFramework::ScreenPoint screenPoint = AztfVi::ScreenPointFromQPoint(m_animViewportWidget->mapFromGlobal(QCursor::pos())); + m_manipulatorManager->DrawManipulators( + *debugDisplay, m_animViewportWidget->GetCameraState(), + AztfVi::BuildMouseInteraction( + AztfVi::BuildMousePick(m_animViewportWidget->GetCameraState(), screenPoint), + AztfVi::MouseButtons(AztfVi::TranslateMouseButtons(QGuiApplication::mouseButtons())), + AztfVi::InteractionId(AZ::EntityId(), m_animViewportWidget->GetViewportContext()->GetId()), keyboardModifiers )); + debugDisplay->DepthTestOn(); + } + + bool AtomRenderPlugin::HandleMouseInteraction( + const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteractionEvent) + { + if (!m_manipulatorManager) + { + return false; + } + + using AzToolsFramework::ViewportInteraction::MouseEvent; + const auto& mouseInteraction = mouseInteractionEvent.m_mouseInteraction; + + switch (mouseInteractionEvent.m_mouseEvent) + { + case MouseEvent::Down: + return m_manipulatorManager->ConsumeViewportMousePress(mouseInteraction); + case MouseEvent::DoubleClick: + return false; + case MouseEvent::Move: + { + const AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult mouseMoveResult = + m_manipulatorManager->ConsumeViewportMouseMove(mouseInteraction); + return mouseMoveResult == AzToolsFramework::ManipulatorManager::ConsumeMouseMoveResult::Interacting; + } + case MouseEvent::Up: + return m_manipulatorManager->ConsumeViewportMouseRelease(mouseInteraction); + case MouseEvent::Wheel: + return m_manipulatorManager->ConsumeViewportMouseWheel(mouseInteraction); + default: + return false; + } + } + // 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 d87e039487..23980ddc0d 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Tools/EMStudio/AtomRenderPlugin.h @@ -9,10 +9,14 @@ #pragma once #if !defined(Q_MOC_RUN) +#include +#include +#include +#include + #include #include #include - #include #include #endif @@ -26,6 +30,7 @@ namespace EMStudio { class AtomRenderPlugin : public DockWidgetPlugin + , private AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus::Handler { public: AZ_CLASS_ALLOCATOR_DECL @@ -53,17 +58,36 @@ namespace EMStudio void ReinitRenderer(); void LoadRenderOptions(); - const RenderOptions* GetRenderOptions() const; + void SaveRenderOptions(); + RenderOptions* GetRenderOptions(); + + void Render(EMotionFX::ActorRenderFlagBitset renderFlags) override; + void SetManipulatorMode(RenderOptions::ManipulatorMode mode); private: + // AzToolsFramework::ViewportInteraction::ViewportMouseRequestBus overrides... + bool HandleMouseInteraction(const AzToolsFramework::ViewportInteraction::MouseInteractionEvent& mouseInteractionEvent) override; + + void SetupManipulators(); + void OnManipulatorMoved(const AZ::Vector3& position); + void OnManipulatorRotated(const AZ::Quaternion& rotation); + void OnManipulatorScaled(const AZ::Vector3& scale, const AZ::Vector3& scaleOffset); QWidget* m_innerWidget = nullptr; AnimViewportWidget* m_animViewportWidget = nullptr; RenderOptions m_renderOptions; + // Manipulators + AzToolsFramework::TranslationManipulators m_translationManipulators; + AzToolsFramework::RotationManipulators m_rotateManipulators; + AzToolsFramework::ScaleManipulators m_scaleManipulators; + AZStd::shared_ptr m_manipulatorManager; + MCORE_DEFINECOMMANDCALLBACK(ImportActorCallback); MCORE_DEFINECOMMANDCALLBACK(RemoveActorCallback); ImportActorCallback* m_importActorCallback = nullptr; RemoveActorCallback* m_removeActorCallback = nullptr; }; + + extern const AzToolsFramework::ManipulatorManagerId g_animManipulatorManagerId; }// namespace EMStudio diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake index 330a3c4af7..0c0589c3cc 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/emotionfx_atom_editor_files.cmake @@ -22,4 +22,6 @@ set(FILES Tools/EMStudio/AnimViewportToolBar.h Tools/EMStudio/AnimViewportToolBar.cpp Tools/EMStudio/AnimViewportRequestBus.h + Tools/EMStudio/AnimViewportInputController.h + Tools/EMStudio/AnimViewportInputController.cpp ) 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 cc344db488..7adea15a99 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 @@ -177,6 +177,10 @@ namespace EMStudio SetNearClipPlaneDistance(other.GetNearClipPlaneDistance()); SetFarClipPlaneDistance(other.GetFarClipPlaneDistance()); SetFOV(other.GetFOV()); + SetRenderFlags(other.GetRenderFlags()); + SetManipulatorMode(other.GetManipulatorMode()); + SetCameraViewMode(other.GetCameraViewMode()); + SetCameraFollowUp(other.GetCameraFollowUp()); return *this; } @@ -247,6 +251,16 @@ namespace EMStudio settings->setValue(s_renderSelectionBoxOptionName, m_renderSelectionBox); settings->setValue("manipulatorMode", static_cast(m_manipulatorMode)); + settings->setValue("cameraViewMode", static_cast(m_cameraViewMode)); + settings->setValue("cameraFollowUp", m_cameraFollowUp); + + // Save render flags + settings->beginGroup("renderFlags"); + for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) + { + settings->setValue(QString(i), (bool)m_renderFlags[i]); + } + settings->endGroup(); } RenderOptions RenderOptions::Load(QSettings* settings) @@ -315,6 +329,18 @@ namespace EMStudio options.m_renderSelectionBox = settings->value(s_renderSelectionBoxOptionName, options.m_renderSelectionBox).toBool(); options.m_manipulatorMode = static_cast(settings->value("manipulatorMode", options.m_manipulatorMode).toInt()); + options.m_cameraViewMode = static_cast(settings->value("cameraViewMode", options.m_cameraViewMode).toInt()); + options.m_cameraFollowUp = settings->value("CameraFollowUp", options.m_cameraFollowUp).toBool(); + + // Read render flags + settings->beginGroup("renderFlags"); + for (uint32 i = 0; i < EMotionFX::ActorRenderFlag::NUM_RENDERFLAGS; ++i) + { + const bool defaultValue = (i == EMotionFX::ActorRenderFlag::RENDER_SOLID); + const bool isEnabled = settings->value(QString(i), defaultValue).toBool(); + options.m_renderFlags[i] = isEnabled; + } + settings->endGroup(); options.CopyToRenderActorSettings(EMotionFX::GetRenderActorSettings()); @@ -1058,6 +1084,41 @@ namespace EMStudio return m_manipulatorMode; } + void RenderOptions::SetCameraViewMode(CameraViewMode mode) + { + m_cameraViewMode = mode; + } + + RenderOptions::CameraViewMode RenderOptions::GetCameraViewMode() const + { + return m_cameraViewMode; + } + + void RenderOptions::SetCameraFollowUp(bool followUp) + { + m_cameraFollowUp = followUp; + } + + bool RenderOptions::GetCameraFollowUp() const + { + return m_cameraFollowUp; + } + + void RenderOptions::ToggerRenderFlag(int index) + { + m_renderFlags[index] = !m_renderFlags[index]; + } + + void RenderOptions::SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags) + { + m_renderFlags = renderFlags; + } + + EMotionFX::ActorRenderFlagBitset RenderOptions::GetRenderFlags() const + { + return m_renderFlags; + } + void RenderOptions::CopyToRenderActorSettings(AZ::Render::RenderActorSettings& settings) const { settings.m_vertexNormalsScale = m_vertexNormalsScale; 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 20d521813d..3c5dbcaba1 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 @@ -15,6 +15,7 @@ #include "../EMStudioConfig.h" #include "../PluginOptions.h" #include "../PluginOptionsBus.h" +#include QT_FORWARD_DECLARE_CLASS(QSettings); @@ -83,6 +84,26 @@ namespace EMStudio static const char* s_lastUsedLayoutOptionName; static const char* s_renderSelectionBoxOptionName; + enum ManipulatorMode + { + SELECT = 0, + TRANSLATE = 1, + ROTATE = 2, + SCALE = 3, + NUM_MODES = 4 + }; + + enum CameraViewMode + { + FRONT, + BACK, + TOP, + BOTTOM, + LEFT, + RIGHT, + DEFAULT + }; + RenderOptions(); ~RenderOptions(); RenderOptions& operator=(const RenderOptions& other); @@ -254,18 +275,19 @@ namespace EMStudio bool GetRenderSelectionBox() const { return m_renderSelectionBox; } void SetRenderSelectionBox(bool renderSelectionBox); - enum ManipulatorMode - { - SELECT = 0, - TRANSLATE = 1, - ROTATE = 2, - SCALE = 3, - NUM_MODES = 4 - }; - void SetManipulatorMode(ManipulatorMode mode); ManipulatorMode GetManipulatorMode() const; + void SetCameraViewMode(CameraViewMode mode); + CameraViewMode GetCameraViewMode() const; + + void SetCameraFollowUp(bool followUp); + bool GetCameraFollowUp() const; + + void ToggerRenderFlag(int index); + void SetRenderFlags(EMotionFX::ActorRenderFlagBitset renderFlags); + EMotionFX::ActorRenderFlagBitset GetRenderFlags() const; + private: void OnGridUnitSizeChangedCallback() const; void OnVertexNormalsScaleChangedCallback() const; @@ -378,10 +400,13 @@ namespace EMStudio AZ::Color m_simulatedObjectColliderColor; AZ::Color m_selectedSimulatedObjectColliderColor; - // The following are not in the UI + // The following are not in the UI AZStd::string m_lastUsedLayout; bool m_renderSelectionBox; - ManipulatorMode m_manipulatorMode = SELECT; + ManipulatorMode m_manipulatorMode = ManipulatorMode::SELECT; + CameraViewMode m_cameraViewMode = CameraViewMode::DEFAULT; + bool m_cameraFollowUp = false; + EMotionFX::ActorRenderFlagBitset m_renderFlags; }; } // namespace EMStudio diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp index 3451855c86..078dd68932 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderPlugin.cpp @@ -709,8 +709,10 @@ namespace EMStudio renderOptionsFilename += "EMStudioRenderOptions.cfg"; QSettings settings(renderOptionsFilename.c_str(), QSettings::IniFormat, this); - // save the general render options - m_renderOptions.Save(&settings); + // Deprecation of renderPlugin. + // Since we are using the same render option save file for atom render plugin, do not save the render options in the RenderPlugin to + // prevent double save. + // m_renderOptions.Save(&settings); AZStd::string groupName; if (m_currentLayout) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp index fe8fb61f02..2215174919 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/RenderPlugin/RenderViewWidget.cpp @@ -50,8 +50,6 @@ namespace EMStudio m_plugin->CreateRenderWidget(this, &m_renderWidget, &renderWidget); verticalLayout->addWidget(renderWidget); - new QActionGroup(this); - QActionGroup* group = new QActionGroup(this); group->setExclusive(true); From aab3d8df67b6d17b92978972936ba92f14d6e756 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Tue, 25 Jan 2022 13:45:30 -0600 Subject: [PATCH 29/36] Converting Landscape Canvas tests to utilize the prefab system (#7142) * Converting LandscapeCanvas automated tests to utilize prefab system Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Finalizing LandscapeCanvas automated test conversions to utilize prefab system Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing test gem from enabled_gems for AutomatedTesting Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing test gem subdirectory that was mistakenly committed Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing debug wait Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- .../landscape_canvas_utils.py | 6 +- .../PythonTests/largeworlds/CMakeLists.txt | 2 +- .../AreaNodes_DependentComponentsAdded.py | 3 +- .../AreaNodes_EntityCreatedOnNodeAdd.py | 4 +- .../AreaNodes_EntityRemovedOnNodeDelete.py | 5 +- .../ComponentUpdates_UpdateGraph.py | 36 ++---- .../EditorScripts/Component_AddedRemoved.py | 4 +- .../Edit_DisabledNodeDuplication.py | 3 +- ...py => Edit_UndoNodeDelete_PrefabEntity.py} | 37 +++--- .../GradientMixer_NodeConstruction.py | 4 +- ...entModifierNodes_EntityCreatedOnNodeAdd.py | 4 +- ...ModifierNodes_EntityRemovedOnNodeDelete.py | 5 +- .../GradientNodes_DependentComponentsAdded.py | 4 +- .../GradientNodes_EntityCreatedOnNodeAdd.py | 4 +- ...GradientNodes_EntityRemovedOnNodeDelete.py | 5 +- .../GraphClosed_OnEntityDelete.py | 5 +- .../GraphClosed_OnLevelChange.py | 7 +- .../EditorScripts/GraphClosed_TabbedGraph.py | 5 +- .../GraphUpdates_UpdateComponents.py | 47 ++++--- .../LayerBlender_NodeConstruction.py | 4 +- .../LayerExtenderNodes_ComponentEntitySync.py | 4 +- .../NewGraph_CreatedSuccessfully.py | 4 +- .../EditorScripts/Prefab_CreateInstantiate.py | 69 ++++++++++ .../ShapeNodes_EntityCreatedOnNodeAdd.py | 7 +- .../ShapeNodes_EntityRemovedOnNodeDelete.py | 5 +- .../EditorScripts/Slice_CreateInstantiate.py | 84 ------------ ...otConnections_UpdateComponentReferences.py | 4 +- .../landscape_canvas/TestSuite_Main.py | 87 +++++++++++-- .../TestSuite_Main_Optimized.py | 104 --------------- .../landscape_canvas/TestSuite_Periodic.py | 121 ------------------ AutomatedTesting/project.json | 2 +- 31 files changed, 229 insertions(+), 456 deletions(-) rename AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/{Edit_UndoNodeDelete_SliceEntity.py => Edit_UndoNodeDelete_PrefabEntity.py} (85%) mode change 100755 => 100644 create mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Prefab_CreateInstantiate.py delete mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py delete mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py delete mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Periodic.py diff --git a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/landscape_canvas_utils.py b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/landscape_canvas_utils.py index d54e32089a..333422815f 100755 --- a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/landscape_canvas_utils.py +++ b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/landscape_canvas_utils.py @@ -19,12 +19,16 @@ def find_nodes_matching_entity_component(component_name, entity_id): :param entity_id: The entity ID to search for the given component node on :return List of matching nodes """ + component_type_id = hydra.get_component_type_id(component_name) component = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', entity_id, - hydra.get_component_type_id(component_name)) + component_type_id) + if component.IsSuccess(): component_id = component.GetValue() component_node = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'GetAllNodesMatchingEntityComponent', component_id) if component_node: print(f"{component_name} node found on entity {entity_id.ToString()}") + else: + print(f"Failed to find {component_name} node on entity {entity_id.ToString()}") return component_node diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index 2e3e72883c..f016094b26 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -43,7 +43,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::LandscapeCanvasTests_Main_Optimized TEST_SERIAL TEST_SUITE main - PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/TestSuite_Main_Optimized.py + PATH ${CMAKE_CURRENT_LIST_DIR}/landscape_canvas/TestSuite_Main.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py index 8151299cea..09dc6d7d0b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py @@ -68,8 +68,7 @@ def AreaNodes_DependentComponentsAdded(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py index f3f4a1862d..95294de2d2 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py @@ -58,7 +58,6 @@ def AreaNodes_EntityCreatedOnNodeAdd(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -67,8 +66,7 @@ def AreaNodes_EntityCreatedOnNodeAdd(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py index f8b0539759..4e5e75b3e1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py @@ -59,8 +59,8 @@ def AreaNodes_EntityRemovedOnNodeDelete(): import azlmbr.math as math import azlmbr.paths + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -73,8 +73,7 @@ def AreaNodes_EntityRemovedOnNodeDelete(): deletedEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py index cc40d8b861..1635365a08 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py @@ -1,15 +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 """ class Tests: - slice_instantiated = ( - "Slice instantiated successfully", - "Failed to instantiate slice" + prefab_instantiated = ( + "Prefab instantiated successfully", + "Failed to instantiate prefab" ) lc_entity_found = ( "LandscapeCanvas entity found", @@ -24,7 +23,7 @@ class Tests: "Failed to find Distribution Filter component on BushSpawner entity" ) existing_graph_opened = ( - "Opened existing graph from slice", + "Opened existing graph from prefab", "Failed to open existing graph" ) dist_filter_node_found = ( @@ -66,10 +65,8 @@ def ComponentUpdates_UpdateGraph(): Summary: This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of Landscape Canvas. - Expected Behavior: Graphs properly reflect component changes made to entities outside of Landscape Canvas. - Test Steps: 1. Open Level 2. Find LandscapeCanvas named entity @@ -83,41 +80,36 @@ def ComponentUpdates_UpdateGraph(): 9. Add a new entity with unique name as a child of the Landscape Canvas entity 10. Add a Box Shape component to the new child entity 11. Ensure Box Shape node is present on the open graph - Note: - This test file must be called from the Open 3D Engine Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. - :return: None """ import os - import azlmbr.asset as asset import azlmbr.bus as bus import azlmbr.editor as editor import azlmbr.entity as entity import azlmbr.legacy.general as general import azlmbr.landscapecanvas as landscapecanvas import azlmbr.math as math - import azlmbr.slice as slice + import azlmbr.prefab as prefab import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper - # Open a simple level and instantiate LC_BushFlowerBlender.slice - helper.init_idle() - helper.open_level("Physics", "Base") + # Open a simple level and instantiate BushFlowerBlender.prefab + hydra.open_base_level() transform = math.Transform_CreateIdentity() position = math.Vector3(64.0, 64.0, 32.0) transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - Report.critical_result(Tests.slice_instantiated, test_slice.IsValid()) + test_prefab_path = os.path.join("Assets", "Prefabs", "BushFlowerBlender.prefab") + prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'InstantiatePrefab', test_prefab_path, + entity.EntityId(), position) + Report.critical_result(Tests.prefab_instantiated, prefab_result.IsSuccess()) # Find root entity in the loaded level search_filter = entity.SearchFilter() @@ -126,8 +118,8 @@ def ComponentUpdates_UpdateGraph(): # Allow a few seconds for matching entity to be found helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) lc_matching_entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) - slice_root_id = lc_matching_entities[0] #Entity with Landscape Canvas component - Report.critical_result(Tests.lc_entity_found, slice_root_id.IsValid()) + prefab_root_id = lc_matching_entities[0] #Entity with Landscape Canvas component + Report.critical_result(Tests.lc_entity_found, prefab_root_id.IsValid()) # Find the BushSpawner entity search_filter.names = ["BushSpawner"] @@ -147,7 +139,7 @@ def ComponentUpdates_UpdateGraph(): # Open Landscape Canvas and the existing graph general.open_pane('Landscape Canvas') - open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + open_graph = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', prefab_root_id) Report.critical_result(Tests.existing_graph_opened, open_graph.IsValid()) # Verify that Distribution Filter node is present on the graph diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py index 7f21a26595..465cf14481 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Component_AddedRemoved.py @@ -45,11 +45,9 @@ def Component_AddedRemoved(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Create an Entity at the root of the level newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py index 4dfc227c53..e5b66399cb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py @@ -59,8 +59,7 @@ def Edit_DisabledNodeDuplication(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_PrefabEntity.py old mode 100755 new mode 100644 similarity index 85% rename from AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py rename to AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_PrefabEntity.py index a26e16755f..d7735f59c2 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_PrefabEntity.py @@ -1,15 +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 """ class Tests: - slice_spawned = ( - "Slice instantiated successfully", - "Failed to instantiate slice" + prefab_instantiated = ( + "Prefab instantiated successfully", + "Failed to instantiate prefab" ) lc_entity_found = ( "Landscape Canvas entity found", @@ -31,31 +30,28 @@ class Tests: "Vegetation Layer Spawner node was successfully removed", "Failed to remove Vegetation Layer Spawner node" ) -def Edit_UndoNodeDelete_SliceEntity(): + + +def Edit_UndoNodeDelete_PrefabEntity(): """ Summary: - This test verifies Editor stability after undoing the deletion of nodes on a slice entity. - + This test verifies Editor stability after undoing the deletion of nodes on a prefab entity. Expected Behavior: Editor remains stable and free of crashes. - Test Steps: 1) Open a simple level - 2) Instantiate a slice with a Landscape Canvas setup + 2) Instantiate a prefab with a Landscape Canvas setup 3) Find a specific node on the graph, and delete it 4) Restore the node with Undo - Note: - This test file must be called from the Open 3D Engine Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. - :return: None """ import os - import azlmbr.asset as asset import azlmbr.bus as bus import azlmbr.editor as editor import azlmbr.entity as entity @@ -63,25 +59,23 @@ def Edit_UndoNodeDelete_SliceEntity(): import azlmbr.editor.graph as graph import azlmbr.landscapecanvas as landscapecanvas import azlmbr.math as math - import azlmbr.slice as slice + import azlmbr.prefab as prefab import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Instantiate slice transform = math.Transform_CreateIdentity() position = math.Vector3(64.0, 64.0, 32.0) transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - Report.result(Tests.slice_spawned, test_slice.IsValid()) + test_prefab_path = os.path.join("Assets", "Prefabs", "BushFlowerBlender.prefab") + prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'InstantiatePrefab', test_prefab_path, + entity.EntityId(), position) + Report.critical_result(Tests.prefab_instantiated, prefab_result.IsSuccess()) # Find root entity in the loaded level search_filter = entity.SearchFilter() @@ -134,5 +128,4 @@ def Edit_UndoNodeDelete_SliceEntity(): if __name__ == "__main__": from editor_python_test_tools.utils import Report - Report.start_test(Edit_UndoNodeDelete_SliceEntity) - + Report.start_test(Edit_UndoNodeDelete_PrefabEntity) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py index c390df7c61..95a9b08fe5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py @@ -76,7 +76,6 @@ def GradientMixer_NodeConstruction(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -85,8 +84,7 @@ def GradientMixer_NodeConstruction(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py index c3952fe34b..3b6e28ca3d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py @@ -58,7 +58,6 @@ def GradientModifierNodes_EntityCreatedOnNodeAdd(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -67,8 +66,7 @@ def GradientModifierNodes_EntityCreatedOnNodeAdd(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py index d7789a21fb..e6fb61e10a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py @@ -58,8 +58,8 @@ def GradientModifierNodes_EntityRemovedOnNodeDelete(): import azlmbr.legacy.general as general import azlmbr.math as math + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -72,8 +72,7 @@ def GradientModifierNodes_EntityRemovedOnNodeDelete(): deletedEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py index 63df9a6fcb..c2007e49e2 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py @@ -60,7 +60,6 @@ def GradientNodes_DependentComponentsAdded(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -69,8 +68,7 @@ def GradientNodes_DependentComponentsAdded(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py index d5595e342c..5111f45f22 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py @@ -58,7 +58,6 @@ def GradientNodes_EntityCreatedOnNodeAdd(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -67,8 +66,7 @@ def GradientNodes_EntityCreatedOnNodeAdd(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py index e5bfbfc7f1..1840fd3f1a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py @@ -58,8 +58,8 @@ def GradientNodes_EntityRemovedOnNodeDelete(): import azlmbr.legacy.general as general import azlmbr.math as math + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -72,8 +72,7 @@ def GradientNodes_EntityRemovedOnNodeDelete(): deletedEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py index 0f83688206..1902516fb3 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py @@ -51,8 +51,8 @@ def GraphClosed_OnEntityDelete(): import azlmbr.editor.graph as graph import azlmbr.legacy.general as general + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -61,8 +61,7 @@ def GraphClosed_OnEntityDelete(): newRootEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py index 67c2ec6908..d5d46c042d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py @@ -51,14 +51,13 @@ def GraphClosed_OnLevelChange(): import azlmbr.editor.graph as graph import azlmbr.legacy.general as general + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') @@ -73,7 +72,7 @@ def GraphClosed_OnLevelChange(): Report.result(Tests.graph_registered, graph_registered) # Open a different level, which should close any open Landscape Canvas graphs - general.open_level_no_prompt('WhiteBox/EmptyLevel') + general.open_level_no_prompt('Base') # Make sure the graph we created is now closed graphIsOpen = graph.AssetEditorRequestBus(bus.Event, 'ContainsGraph', editorId, newGraphId) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py index 83762e0afb..d33ee7746f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py @@ -51,8 +51,8 @@ def GraphClosed_TabbedGraphClosesIndependently(): import azlmbr.editor.graph as graph import azlmbr.legacy.general as general + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editor_id = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -65,8 +65,7 @@ def GraphClosed_TabbedGraphClosesIndependently(): return graph_open # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py index c489c738d5..6a007a9014 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py @@ -1,18 +1,17 @@ """ 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: - slice_instantiated = ( - "Slice instantiated successfully", - "Failed to instantiate slice" + prefab_instantiated = ( + "Prefab instantiated successfully", + "Failed to instantiate prefab" ) existing_graph_opened = ( - "Opened existing graph from slice", + "Opened existing graph from prefab", "Failed to open existing graph" ) node_removed = ( @@ -37,13 +36,11 @@ def GraphUpdates_UpdateComponent(): """ Summary: This test verifies that components are properly updated as nodes are added/removed/updated. - Expected Behavior: Landscape Canvas node CRUD properly updates component entities. - Test Steps: 1. Open Level. - 2. Open the graph on LC_BushFlowerBlender.slice + 2. Open the graph on BushFlowerBlender.prefab 3. Find the Rotation Modifier node on the BushSpawner entity 4. Delete the Rotation Modifier node 5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity @@ -51,18 +48,15 @@ def GraphUpdates_UpdateComponent(): 7. Ensure BushSpawner entity is deleted 8. Change connection from second Rotation Modifier node to a different Gradient 9. Ensure Gradient reference on component is updated - Note: - This test file must be called from the Open 3D Engine Editor command terminal - Any passed and failed tests are written to the Editor.log file. Parsing the file or running a log_monitor are required to observe the test results. - :return: None """ import os - import azlmbr.asset as asset import azlmbr.bus as bus import azlmbr.editor as editor import azlmbr.entity as entity @@ -70,39 +64,37 @@ def GraphUpdates_UpdateComponent(): import azlmbr.editor.graph as graph import azlmbr.landscapecanvas as landscapecanvas import azlmbr.math as math - import azlmbr.slice as slice + import azlmbr.prefab as prefab import automatedtesting_shared.landscape_canvas_utils as lc import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper - # Open a simple level and instantiate LC_BushFlowerBlender.slice - helper.init_idle() - helper.open_level("Physics", "Base") + # Open a simple level and instantiate BushFlowerBlender.prefab + hydra.open_base_level() transform = math.Transform_CreateIdentity() position = math.Vector3(64.0, 64.0, 32.0) transform.invoke('SetPosition', position) - test_slice_path = os.path.join("Slices", "LC_BushFlowerBlender.slice") - test_slice_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", test_slice_path, math.Uuid(), - False) - test_slice = slice.SliceRequestBus(bus.Broadcast, 'InstantiateSliceFromAssetId', test_slice_id, transform) - Report.critical_result(Tests.slice_instantiated, test_slice.IsValid()) + test_prefab_path = os.path.join("Assets", "Prefabs", "BushFlowerBlender.prefab") + prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'InstantiatePrefab', test_prefab_path, + entity.EntityId(), position) + Report.critical_result(Tests.prefab_instantiated, prefab_result.IsSuccess()) - # Search for root entity to ensure slice is loaded + # Search for root entity to ensure prefab is loaded search_filter = entity.SearchFilter() search_filter.names = ["LandscapeCanvas"] helper.wait_for_condition(lambda: len(entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)) > 0, 5.0) + prefab_lc_root = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter)[0] # Find needed entities in the loaded level - slice_root_id = hydra.find_entity_by_name('LandscapeCanvas') bush_spawner_id = hydra.find_entity_by_name('BushSpawner') flower_spawner_id = hydra.find_entity_by_name('FlowerSpawner') inverted_perlin_noise_id = hydra.find_entity_by_name('Invert') # Open Landscape Canvas and the existing graph general.open_pane('Landscape Canvas') - open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', slice_root_id) + open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', prefab_lc_root) Report.critical_result(Tests.existing_graph_opened, open_graph_id.IsValid()) # Find the Rotation Modifier node on the BushSpawner entity @@ -110,6 +102,7 @@ def GraphUpdates_UpdateComponent(): # Remove the Rotation Modifier node graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, rotation_modifier_node[0]) + general.idle_wait_frames(2) # Verify node was removed rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', bush_spawner_id) @@ -121,14 +114,18 @@ def GraphUpdates_UpdateComponent(): Report.result(Tests.component_removed, not has_rotation_modifier) # Find the Vegetation Layer Spawner node on the BushSpawner entity + open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', prefab_lc_root) layer_spawner_node = lc.find_nodes_matching_entity_component('Vegetation Layer Spawner', bush_spawner_id) # Remove the Vegetation Layer Spawner node and verify the corresponding entity is deleted graph.GraphControllerRequestBus(bus.Event, 'RemoveNode', open_graph_id, layer_spawner_node[0]) + general.idle_wait_frames(2) + layer_spawner_node = lc.find_nodes_matching_entity_component('Vegetation Layer Spawner', bush_spawner_id) bush_spawner_id = hydra.find_entity_by_name('BushSpawner') - Report.result(Tests.entity_deleted, not bush_spawner_id) + Report.result(Tests.entity_deleted, not layer_spawner_node and not bush_spawner_id) # Connect the FlowerSpawner's Rotation Modifier node to the Invert Gradient Modifier node + open_graph_id = landscapecanvas.LandscapeCanvasRequestBus(bus.Broadcast, 'OnGraphEntity', prefab_lc_root) rotation_modifier_node = lc.find_nodes_matching_entity_component('Vegetation Rotation Modifier', flower_spawner_id) invert_node = lc.find_nodes_matching_entity_component('Invert Gradient Modifier', inverted_perlin_noise_id) @@ -137,7 +134,7 @@ def GraphUpdates_UpdateComponent(): graph.GraphControllerRequestBus(bus.Event, 'AddConnectionBySlotId', open_graph_id, invert_node[0], outbound_gradient_slot, rotation_modifier_node[0], inbound_gradient_z_slot) - general.idle_wait(1.0) # Add a small wait to ensure component property has time to update + general.idle_wait_frames(2) # Add a small wait to ensure component property has time to update # Verify the Gradient Entity Id reference on the Rotation Modifier component was properly set rotation_type_id = hydra.get_component_type_id('Vegetation Rotation Modifier') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py index b2bf20411b..da9a21aee6 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py @@ -64,7 +64,6 @@ def LayerBlender_NodeConstruction(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -73,8 +72,7 @@ def LayerBlender_NodeConstruction(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py index 510c404614..cd54a741ec 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py @@ -63,7 +63,6 @@ def LayerExtenderNodes_ComponentEntitySync(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -72,8 +71,7 @@ def LayerExtenderNodes_ComponentEntitySync(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py index d13c5dfa2f..f7564a643d 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/NewGraph_CreatedSuccessfully.py @@ -60,7 +60,6 @@ def NewGraph_CreatedSuccessfully(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -69,8 +68,7 @@ def NewGraph_CreatedSuccessfully(): new_root_entity_id = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Listen for entity creation notifications so we can check if the entity created # with the new graph has our Landscape Canvas component automatically added diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Prefab_CreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Prefab_CreateInstantiate.py new file mode 100644 index 0000000000..894a69a40e --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Prefab_CreateInstantiate.py @@ -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 +""" + + +class Tests: + prefab_created = ( + "Prefab created successfully", + "Failed to create prefab" + ) + prefab_instantiated = ( + "Prefab instantiated successfully", + "Failed to instantiate prefab" + ) + + +def Prefab_CreateInstantiate(): + """ + Summary: + A prefab containing the LandscapeCanvas component can be created/instantiated. + Expected Result: + Prefab is created/processed/instantiated successfully and free of errors/warnings. + Test Steps: + 1) Open a simple level + 2) Create a new entity with a Landscape Canvas component + 3) Create a prefab of the new entity + 4) Instantiate a new copy of the prefab + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + :return: None + """ + + import azlmbr.math as math + + import editor_python_test_tools.hydra_editor_utils as hydra + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import TestHelper as helper + from editor_python_test_tools.prefab_utils import Prefab + + # Open an existing simple level + hydra.open_base_level() + + # Create entity with Landscape Canvas component + position = math.Vector3(512.0, 512.0, 32.0) + landscape_canvas = hydra.Entity("landscape_canvas_entity") + landscape_canvas.create_entity(position, ["Landscape Canvas"]) + + # Create in-memory prefab from the created entity + lc_prefab_filename = "LC_PrefabTest" + lc_prefab, lc_prefab_instance = Prefab.create_prefab([landscape_canvas], lc_prefab_filename) + + # Verify if prefab is created + helper.wait_for_condition(lambda: lc_prefab.is_prefab_loaded(lc_prefab_filename), 5.0) + Report.result(Tests.prefab_created, lc_prefab.is_prefab_loaded(lc_prefab_filename)) + + # Instantiate prefab + lc_prefab_instance2 = lc_prefab.instantiate() + helper.wait_for_condition(lambda: lc_prefab_instance2.has_editor_prefab_component(), 5.0) + Report.result(Tests.prefab_instantiated, lc_prefab_instance2.has_editor_prefab_component()) + + +if __name__ == "__main__": + + from editor_python_test_tools.utils import Report + Report.start_test(Prefab_CreateInstantiate) \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py index 93464c7ad3..c93b377945 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py @@ -58,7 +58,6 @@ def ShapeNodes_EntityCreatedOnNodeAdd(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -66,10 +65,8 @@ def ShapeNodes_EntityCreatedOnNodeAdd(): global newEntityId newEntityId = parameters[0] - # Open an existing simple level - - helper.init_idle() - helper.open_level("Physics", "Base") + # Open an existing simple level + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py index d2708f643d..4057e7f6e9 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py @@ -58,8 +58,8 @@ def ShapeNodes_EntityRemovedOnNodeDelete(): import azlmbr.legacy.general as general import azlmbr.math as math + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -72,8 +72,7 @@ def ShapeNodes_EntityRemovedOnNodeDelete(): deletedEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py deleted file mode 100644 index c5ab08f99a..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Slice_CreateInstantiate.py +++ /dev/null @@ -1,84 +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 -""" - - -class Tests: - slice_created = ( - "Slice created successfully", - "Failed to create slice" - ) - slice_instantiated = ( - "Slice instantiated successfully", - "Failed to instantiate slice" - ) - - -def Slice_CreateInstantiate(): - """ - Summary: - A slice containing the LandscapeCanvas component can be created/instantiated. - - Expected Result: - Slice is created/processed/instantiated successfully and free of errors/warnings. - - Test Steps: - 1) Open a simple level - 2) Create a new entity with a Landscape Canvas component - 3) Create a slice of the new entity - 4) Instantiate a new copy of the slice - - Note: - - This test file must be called from the Open 3D Engine Editor command terminal - - Any passed and failed tests are written to the Editor.log file. - Parsing the file or running a log_monitor are required to observe the test results. - :return: None - """ - - import os - - import azlmbr.math as math - import azlmbr.bus as bus - import azlmbr.asset as asset - import azlmbr.slice as slice - - import editor_python_test_tools.hydra_editor_utils as hydra - from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper - - def path_is_valid_asset(asset_path): - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False) - return asset_id.invoke("IsValid") - - # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") - - # Create entity with Landscape Canvas component - position = math.Vector3(512.0, 512.0, 32.0) - landscape_canvas = hydra.Entity("landscape_canvas_entity") - landscape_canvas.create_entity(position, ["Landscape Canvas"]) - - # Create slice from the created entity - slice_path = os.path.join("slices", "TestSlice.slice") - slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", landscape_canvas.id, slice_path) - - # Verify if slice is created - helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0) - Report.result(Tests.slice_created, path_is_valid_asset(slice_path)) - - # Instantiate slice - transform = math.Transform_CreateIdentity() - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", slice_path, math.Uuid(), False) - test_slice = slice.SliceRequestBus(bus.Broadcast, "InstantiateSliceFromAssetId", asset_id, transform) - helper.wait_for_condition(lambda: test_slice.IsValid(), 5.0) - Report.result(Tests.slice_instantiated, test_slice.IsValid()) - - -if __name__ == "__main__": - - from editor_python_test_tools.utils import Report - Report.start_test(Slice_CreateInstantiate) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py index 3169908621..208849ea61 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py @@ -67,7 +67,6 @@ def SlotConnections_UpdateComponentReferences(): import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper editorId = azlmbr.globals.property.LANDSCAPE_CANVAS_EDITOR_ID @@ -101,8 +100,7 @@ def SlotConnections_UpdateComponentReferences(): newEntityId = parameters[0] # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main.py index dedc9c70c0..12e426e400 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main.py @@ -1,29 +1,88 @@ """ Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os import pytest -import sys -import ly_test_tools.environment.file_system as file_system - -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') -from base import TestAutomationBase +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite -@pytest.mark.SUITE_main @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(TestAutomationBase): +class TestAutomation(EditorTestSuite): - def test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) + class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module - def test_LandscapeCanvas_GradientMixer_NodeConstruction(self, request, workspace, editor, launcher_platform): + class test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_Component_AddedRemoved(EditorSharedTest): + from .EditorScripts import Component_AddedRemoved as test_module + + class test_LandscapeCanvas_ComponentUpdates_UpdateGraph(EditorSharedTest): + from .EditorScripts import ComponentUpdates_UpdateGraph as test_module + + class test_LandscapeCanvas_Edit_DisabledNodeDuplication(EditorSharedTest): + from .EditorScripts import Edit_DisabledNodeDuplication as test_module + + class test_LandscapeCanvas_Edit_UndoNodeDelete_PrefabEntity(EditorSharedTest): + from .EditorScripts import Edit_UndoNodeDelete_PrefabEntity as test_module + + class test_LandscapeCanvas_GradientMixer_NodeConstruction(EditorSharedTest): from .EditorScripts import GradientMixer_NodeConstruction as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) + + class test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module + + class test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") + class test_LandscapeCanvas_GraphClosed_OnEntityDelete(EditorSharedTest): + from .EditorScripts import GraphClosed_OnEntityDelete as test_module + + class test_LandscapeCanvas_GraphClosed_OnLevelChange(EditorSharedTest): + from .EditorScripts import GraphClosed_OnLevelChange as test_module + + class test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(EditorSharedTest): + from .EditorScripts import GraphClosed_TabbedGraph as test_module + + @pytest.mark.skip(reason="https://github.com/o3de/o3de/issues/7141" "https://github.com/o3de/o3de/issues/4872") + class test_LandscapeCanvas_GraphUpdates_UpdateComponents(EditorSharedTest): + from .EditorScripts import GraphUpdates_UpdateComponents as test_module + + class test_LandscapeCanvas_LayerBlender_NodeConstruction(EditorSharedTest): + from .EditorScripts import LayerBlender_NodeConstruction as test_module + + class test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(EditorSharedTest): + from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module + + class test_LandscapeCanvas_NewGraph_CreatedSuccessfully(EditorSharedTest): + from .EditorScripts import NewGraph_CreatedSuccessfully as test_module + + class test_LandscapeCanvas_Prefab_CreateInstantiate(EditorSharedTest): + from .EditorScripts import Prefab_CreateInstantiate as test_module + + class test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(EditorSharedTest): + from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module + + class test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(EditorSharedTest): + from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module + + class test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(EditorSharedTest): + from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py deleted file mode 100644 index e501b3ad3b..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import pytest - -import ly_test_tools.environment.file_system as file_system -import ly_test_tools._internal.pytest_plugin as internal_plugin -from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite - -@pytest.mark.SUITE_periodic -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomationWithPrefabSystemEnabled(EditorTestSuite): - - class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest): - from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module - -@pytest.mark.SUITE_periodic -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(EditorTestSuite): - - enable_prefab_system = False - - class test_LandscapeCanvas_SlotConnections_UpdateComponentReferences(EditorSharedTest): - from .EditorScripts import SlotConnections_UpdateComponentReferences as test_module - - class test_LandscapeCanvas_GradientMixer_NodeConstruction(EditorSharedTest): - from .EditorScripts import GradientMixer_NodeConstruction as test_module - - class test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(EditorSharedTest): - from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module - - class test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(EditorSharedTest): - from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module - - class test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(EditorSharedTest): - from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module - - class test_LandscapeCanvas_Edit_DisabledNodeDuplication(EditorSharedTest): - from .EditorScripts import Edit_DisabledNodeDuplication as test_module - - class test_LandscapeCanvas_Edit_UndoNodeDelete_SliceEntity(EditorSharedTest): - from .EditorScripts import Edit_UndoNodeDelete_SliceEntity as test_module - - class test_LandscapeCanvas_NewGraph_CreatedSuccessfully(EditorSharedTest): - from .EditorScripts import NewGraph_CreatedSuccessfully as test_module - - class test_LandscapeCanvas_Component_AddedRemoved(EditorSharedTest): - from .EditorScripts import Component_AddedRemoved as test_module - - class test_LandscapeCanvas_GraphClosed_OnLevelChange(EditorSharedTest): - from .EditorScripts import GraphClosed_OnLevelChange as test_module - - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") - class test_LandscapeCanvas_GraphClosed_OnEntityDelete(EditorSharedTest): - from .EditorScripts import GraphClosed_OnEntityDelete as test_module - - class test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(EditorSharedTest): - from .EditorScripts import GraphClosed_TabbedGraph as test_module - - class test_LandscapeCanvas_Slice_CreateInstantiate(EditorSingleTest): - from .EditorScripts import Slice_CreateInstantiate as test_module - # Custom teardown to remove slice asset created during test - def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): - file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices", - "TestSlice.slice")], True, True) - - class test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(EditorSharedTest): - from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module - - class test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(EditorSharedTest): - from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module - - class test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(EditorSharedTest): - from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module - - class test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(EditorSharedTest): - from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module - - class test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(EditorSharedTest): - from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module - - @pytest.mark.skipif("debug" == os.path.basename(internal_plugin.build_directory), - reason="https://github.com/o3de/o3de/issues/4872") - class test_LandscapeCanvas_GraphUpdates_UpdateComponents(EditorSharedTest): - from .EditorScripts import GraphUpdates_UpdateComponents as test_module - - class test_LandscapeCanvas_ComponentUpdates_UpdateGraph(EditorSharedTest): - from .EditorScripts import ComponentUpdates_UpdateGraph as test_module - - class test_LandscapeCanvas_LayerBlender_NodeConstruction(EditorSharedTest): - from .EditorScripts import LayerBlender_NodeConstruction as test_module - - class test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(EditorSharedTest): - from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module - - class test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(EditorSharedTest): - from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Periodic.py deleted file mode 100644 index a719b1a7c0..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Periodic.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import pytest -import sys - -import ly_test_tools.environment.file_system as file_system - -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') -from base import TestAutomationBase - - -@pytest.fixture -def remove_test_slice(request, workspace, project): - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice.slice")], True, True) - - def teardown(): - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice.slice")], True, - True) - - request.addfinalizer(teardown) - - -@pytest.mark.SUITE_periodic -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(TestAutomationBase): - - def test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_AreaNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AreaNodes_EntityRemovedOnNodeDelete as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_LayerExtenderNodes_ComponentEntitySync(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerExtenderNodes_ComponentEntitySync as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_Edit_DisabledNodeDuplication(self, request, workspace, editor, launcher_platform): - from .EditorScripts import Edit_DisabledNodeDuplication as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_Edit_UndoNodeDelete_SliceEntity(self, request, workspace, editor, launcher_platform): - from .EditorScripts import Edit_UndoNodeDelete_SliceEntity as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_NewGraph_CreatedSuccessfully(self, request, workspace, editor, launcher_platform): - from .EditorScripts import NewGraph_CreatedSuccessfully as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_Component_AddedRemoved(self, request, workspace, editor, launcher_platform): - from .EditorScripts import Component_AddedRemoved as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GraphClosed_OnLevelChange(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GraphClosed_OnLevelChange as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2201") - def test_LandscapeCanvas_GraphClosed_OnEntityDelete(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GraphClosed_OnEntityDelete as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GraphClosed_TabbedGraphClosesIndependently(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GraphClosed_TabbedGraph as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_Slice_CreateInstantiate(self, request, workspace, editor, remove_test_slice, launcher_platform): - from .EditorScripts import Slice_CreateInstantiate as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GradientModifierNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientModifierNodes_EntityCreatedOnNodeAdd as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GradientModifierNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientModifierNodes_EntityRemovedOnNodeDelete as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GradientNodes_DependentComponentsAdded(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientNodes_DependentComponentsAdded as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GradientNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientNodes_EntityCreatedOnNodeAdd as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GradientNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientNodes_EntityRemovedOnNodeDelete as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_GraphUpdates_UpdateComponents(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GraphUpdates_UpdateComponents as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_ComponentUpdates_UpdateGraph(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ComponentUpdates_UpdateGraph as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_LayerBlender_NodeConstruction(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerBlender_NodeConstruction as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_ShapeNodes_EntityCreatedOnNodeAdd(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ShapeNodes_EntityCreatedOnNodeAdd as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LandscapeCanvas_ShapeNodes_EntityRemovedOnNodeDelete(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ShapeNodes_EntityRemovedOnNodeDelete as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) diff --git a/AutomatedTesting/project.json b/AutomatedTesting/project.json index 5a4b303570..a928547f20 100644 --- a/AutomatedTesting/project.json +++ b/AutomatedTesting/project.json @@ -16,4 +16,4 @@ "external_subdirectories": [ "Gem" ] -} \ No newline at end of file +} From 50015f85999d3c175e8931c3977ab1b0cc6b6a15 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Tue, 25 Jan 2022 12:00:30 -0800 Subject: [PATCH 30/36] Add icon support for the Breadcrumbs UI Component, use it in the Prefab Focus Mode breadcrumbs. (#7136) * Add icon support for the Breadcrumbs UI Component, use it in the prefab focus mode breadcrumb. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Simplified iconAt logic Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Components/Widgets/BreadCrumbs.cpp | 65 +++++++++++++++++-- .../Components/Widgets/BreadCrumbs.h | 16 +++++ .../Prefab/PrefabViewportFocusPathHandler.cpp | 6 ++ 3 files changed, 80 insertions(+), 7 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.cpp index 7ea06c0632..fae6340cec 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.cpp @@ -12,13 +12,12 @@ AZ_PUSH_DISABLE_WARNING(4244 4251, "-Wunknown-warning-option") // 4251: 'QLayoutItem::align': class 'QFlags' needs to have dll-interface to be used by clients of class 'QLayoutItem' #include -#include -#include #include -#include -#include #include #include +#include +#include +#include AZ_POP_DISABLE_WARNING namespace AzQtComponents @@ -46,7 +45,7 @@ namespace AzQtComponents m_label = new QLabel(this); m_label->setObjectName(g_labelName); boxLayout->addWidget(m_label); - m_label->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + m_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); connect(m_label, &QLabel::linkActivated, this, &BreadCrumbs::onLinkActivated); } @@ -82,9 +81,38 @@ namespace AzQtComponents // clean up the path to use all the first separator in the list of separators m_currentPath.replace(g_windowsSeparator, g_separator); + // update internals + m_currentPathSize = m_currentPath.split(g_separator, Qt::SkipEmptyParts).size(); + m_currentPathIcons.resize(m_currentPathSize); + fillLabel(); } + void BreadCrumbs::setDefaultIcon(const QString& icon) + { + m_defaultIcon = icon; + } + + void BreadCrumbs::setIconAt(int index, const QString& icon) + { + if (index < 0 || index >= m_currentPathSize) + { + return; + } + + m_currentPathIcons[index] = icon; + } + + QIcon BreadCrumbs::iconAt(int index) + { + if (index < 0 || index >= m_currentPathSize || m_currentPathIcons[index].isNull()) + { + return QIcon(m_defaultIcon); + } + + return QIcon(m_currentPathIcons[index]); + } + bool BreadCrumbs::getPushPathOnLinkActivation() const { return m_pushPathOnLinkActivation; @@ -220,6 +248,26 @@ namespace AzQtComponents QWidget::resizeEvent(event); } + QString BreadCrumbs::generateIconHtml(int index) + { + QString imagePath; + + if (index >= 0 && index < m_currentPathIcons.size()) + { + imagePath = m_currentPathIcons[index]; + } + + if (imagePath.isEmpty()) + { + imagePath = m_defaultIcon; + } + + return !imagePath.isEmpty() ? QStringLiteral("%2%2") + .arg(imagePath) + .arg(" ") + : ""; + } + void BreadCrumbs::fillLabel() { QString htmlString = ""; @@ -247,7 +295,10 @@ namespace AzQtComponents plainTextPath = m_truncatedPaths.takeLast(); } - htmlString.prepend(plainTextPath); + int index = m_currentPathSize - 1; + + htmlString.prepend(generateIconHtml(index) + plainTextPath); + --index; while (!m_truncatedPaths.isEmpty()) { @@ -262,7 +313,7 @@ namespace AzQtComponents const QString linkPath = buildPathFromList(fullPath, m_truncatedPaths.size()); const QString& part = m_truncatedPaths.takeLast(); - htmlString.prepend(QString("%1").arg(formatLink(linkPath, part))); + htmlString.prepend(QString("%1%2").arg(generateIconHtml(index--)).arg(formatLink(linkPath, part))); } m_label->setText(htmlString); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.h index 4ecbb59647..14391883d5 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/BreadCrumbs.h @@ -78,6 +78,13 @@ namespace AzQtComponents //! Sets the current breadcrumb path without updating the navigation stack. void setCurrentPath(const QString& newPath); + //! Sets a default icon for path elements. + void setDefaultIcon(const QString& iconPath); + //! Sets an icon for the path element at index. + void setIconAt(int index, const QString& iconPath); + //! Gets the icon for the path element at index. + QIcon iconAt(int index); + //! Returns true if activating a link should automatically push a new path to the navigation stack. bool getPushPathOnLinkActivation() const; //! Sets whether activating a link should automatically push a new path to the navigation stack. @@ -134,6 +141,7 @@ namespace AzQtComponents void onLinkActivated(const QString& link); private: + QString generateIconHtml(int index); void fillLabel(); void changePath(const QString& newPath); @@ -155,6 +163,14 @@ namespace AzQtComponents QStringList m_truncatedPaths; AZ_POP_DISABLE_WARNING bool m_pushPathOnLinkActivation = true; + int m_currentPathSize = 0; + + QString m_defaultIcon; + AZ_PUSH_DISABLE_WARNING( + 4251, "-Wunknown-warning-option") // 4251: 'AzQtComponents::BreadCrumbs::m_currentPathIcons': class 'QVector' needs to have + // dll-interface to be used by clients of class 'AzQtComponents::BreadCrumbs' + QVector m_currentPathIcons; + AZ_POP_DISABLE_WARNING friend class Style; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 275079371a..5cff5127df 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -44,6 +44,9 @@ namespace AzToolsFramework::Prefab m_breadcrumbsWidget = breadcrumbsWidget; m_backButton = backButton; + // Add icons to the widget + m_breadcrumbsWidget->setDefaultIcon(QString(":/Entity/prefab_edit.svg")); + // If a part of the path is clicked, focus on that instance connect(m_breadcrumbsWidget, &AzQtComponents::BreadCrumbs::linkClicked, this, [&](const QString&, int linkIndex) @@ -74,6 +77,9 @@ namespace AzToolsFramework::Prefab // Push new Path m_breadcrumbsWidget->pushPath(m_prefabFocusPublicInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str()); + // Set root icon + m_breadcrumbsWidget->setIconAt(0, QString(":/Level/level.svg")); + // If root instance is focused, disable the back button; else enable it. m_backButton->setEnabled(m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId) > 1); } From 1e9c1cdf1fc221e90f248232c74ff93d1c26a936 Mon Sep 17 00:00:00 2001 From: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> Date: Tue, 25 Jan 2022 13:34:56 -0800 Subject: [PATCH 31/36] Android devices have alignment issue with ASTC_6X6 textures. Swith to ASTC_4X4 to fix this issue. (#7144) The astc_6x6 alignment issue will be investiagte seperately. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> --- Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset | 2 +- .../ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset | 2 +- .../Assets/Config/AlbedoWithGenericAlpha.preset | 2 +- .../Asset/ImageProcessingAtom/Assets/Config/Emissive.preset | 2 +- .../Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset | 2 +- .../Assets/Config/UserInterface_Compressed.preset | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset index dc1f38d2da..f3745a3d1c 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset @@ -19,7 +19,7 @@ "UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", "Name": "Albedo", "RGB_Weight": "CIEXYZ", - "PixelFormat": "ASTC_6x6", + "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "DiscardAlpha": true, "IsPowerOf2": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset index 439a057410..6f2f46404e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset @@ -18,7 +18,7 @@ "UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}", "Name": "AlbedoWithCoverage", "RGB_Weight": "CIEXYZ", - "PixelFormat": "ASTC_6x6", + "PixelFormat": "ASTC_4x4", "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset index 3340fd39e4..1d0701a73a 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset @@ -17,7 +17,7 @@ "UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", "Name": "AlbedoWithGenericAlpha", "RGB_Weight": "CIEXYZ", - "PixelFormat": "ASTC_6x6", + "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "MipMapSetting": { "MipGenType": "Box" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset index 798b8d1657..edbe50b220 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset @@ -15,7 +15,7 @@ "UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}", "Name": "Emissive", "RGB_Weight": "CIEXYZ", - "PixelFormat": "ASTC_6x6", + "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "DiscardAlpha": true }, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset index 9e3c718978..de370fda29 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset @@ -20,7 +20,7 @@ "Name": "Reflectance", "SourceColor": "Linear", "DestColor": "Linear", - "PixelFormat": "ASTC_6x6", + "PixelFormat": "ASTC_4x4", "Swizzle": "rrr1", "MaxTextureSize": 2048, "IsPowerOf2": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset index 7e2c42fa6b..cd1b00b2fb 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset @@ -16,7 +16,7 @@ "UUID": "{2828FBFE-BDF9-45A7-9370-F93822719CCF}", "Name": "UserInterface_Compressed", "SuppressEngineReduce": true, - "PixelFormat": "ASTC_6x6" + "PixelFormat": "ASTC_4x4" }, "ios": { "UUID": "{2828FBFE-BDF9-45A7-9370-F93822719CCF}", From dbf9e3f0e516bebe297ad9a35d2013c4950b5844 Mon Sep 17 00:00:00 2001 From: Chris Burel Date: Tue, 25 Jan 2022 14:20:49 -0800 Subject: [PATCH 32/36] Move Android-specific AzFramework dependency of AzTestRunner to Android platform include file (#7151) Signed-off-by: Chris Burel --- Code/Tools/AzTestRunner/CMakeLists.txt | 1 - .../AzTestRunner/Platform/Android/platform_android.cmake | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Code/Tools/AzTestRunner/CMakeLists.txt b/Code/Tools/AzTestRunner/CMakeLists.txt index 2bd74fa1a1..48afe9723c 100644 --- a/Code/Tools/AzTestRunner/CMakeLists.txt +++ b/Code/Tools/AzTestRunner/CMakeLists.txt @@ -27,7 +27,6 @@ if(PAL_TRAIT_AZTESTRUNNER_SUPPORTED AND NOT LY_MONOLITHIC_GAME) PRIVATE AZ::AzCore AZ::AzTest - AZ::AzFramework ) if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) diff --git a/Code/Tools/AzTestRunner/Platform/Android/platform_android.cmake b/Code/Tools/AzTestRunner/Platform/Android/platform_android.cmake index b3bd825b53..bdca5388ef 100644 --- a/Code/Tools/AzTestRunner/Platform/Android/platform_android.cmake +++ b/Code/Tools/AzTestRunner/Platform/Android/platform_android.cmake @@ -10,3 +10,8 @@ set(LY_INCLUDE_DIRECTORIES PRIVATE ${LY_NDK_NATIVE_APP_GLUE_SRC_DIR} ) + +set(LY_BUILD_DEPENDENCIES + PRIVATE + AZ::AzFramework +) From 99764df120c2829a4d02016f2a2c7af0644d0a7c Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Tue, 25 Jan 2022 14:44:24 -0800 Subject: [PATCH 33/36] Fix GCC Build Errors - Fix gcc error caused by implicit conversion of Qt::ByteArray to const char* - Fix Linker errors to QtTest in AtomToolsFramework.Tests and ScriptCanvasDeveloper.Editor Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- .../AzToolsFramework/Entity/EditorEntityContextComponent.cpp | 2 +- Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt | 1 + Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp index 95b3f2bf93..afbc9a4790 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp @@ -447,7 +447,7 @@ namespace AzToolsFramework else { loadedSuccessfully = static_cast(m_entityOwnershipService.get())->LoadFromStream( - stream, AZStd::string_view(levelPakFile.toUtf8(), levelPakFile.size()) ); + stream, AZStd::string_view(levelPakFile.toUtf8().constData(), levelPakFile.size()) ); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index 0fc896e88a..f35663aef2 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -81,6 +81,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) Tests BUILD_DEPENDENCIES PRIVATE + 3rdParty::Qt::Test AZ::AzTest AZ::AzTestShared AZ::AzFrameworkTestShared diff --git a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt index 6271531e97..65f2e66b0b 100644 --- a/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt +++ b/Gems/ScriptCanvasDeveloper/Code/CMakeLists.txt @@ -74,6 +74,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) ${SCRIPT_CANVAS_DEV_COMMON_DEFINES} BUILD_DEPENDENCIES PRIVATE + 3rdParty::Qt::Test AZ::AzCore AZ::AzFramework AZ::AzToolsFramework From 8766de21cc0b7cf9e46fdd01656fb770dcfa2122 Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Tue, 25 Jan 2022 14:53:16 -0800 Subject: [PATCH 34/36] Only use a deterministic random when network option is enabled. (#7126) * Only use a deterministic random when network option is enabled. Signed-off-by: rhhong * use actor instance id as the seed of the lcg random in anim graph instance Signed-off-by: rhhong * add const Signed-off-by: rhhong --- .../Code/EMotionFX/Source/AnimGraphInstance.cpp | 3 +++ .../EMotionFX/Source/AnimGraphTimeCondition.cpp | 11 ++--------- Gems/EMotionFX/Code/MCore/Source/Random.h | 16 ---------------- 3 files changed, 5 insertions(+), 25 deletions(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphInstance.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphInstance.cpp index 7f9e8ba6fc..61a366f298 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphInstance.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphInstance.cpp @@ -71,6 +71,9 @@ namespace EMotionFX // create the parameter value objects CreateParameterValues(); + // Assign a unique seed for the lcg random number. Here we use the actorInstanceId because it guaranteed to be unique and available on actor instances. + m_lcgRandom.SetSeed(actorInstance->GetID()); + m_animGraph->Unlock(); GetEventManager().OnCreateAnimGraphInstance(this); } diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphTimeCondition.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphTimeCondition.cpp index 3da55ced3e..e6e9c529df 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphTimeCondition.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/AnimGraphTimeCondition.cpp @@ -90,15 +90,8 @@ namespace EMotionFX if (m_useRandomization) { // create a randomized count down value - if (animGraphInstance->IsNetworkEnabled()) - { - // using a seeded random in order to generate predictable result in network. - uniqueData->m_countDownTime = MCore::Random::RandF(m_minRandomTime, m_maxRandomTime, animGraphInstance->GetLcgRandom()); - } - else - { - uniqueData->m_countDownTime = MCore::Random::RandF(m_minRandomTime, m_maxRandomTime); - } + uniqueData->m_countDownTime = + m_minRandomTime + (m_maxRandomTime - m_minRandomTime) * animGraphInstance->GetLcgRandom().GetRandomFloat(); } else { diff --git a/Gems/EMotionFX/Code/MCore/Source/Random.h b/Gems/EMotionFX/Code/MCore/Source/Random.h index 55576bb958..d2454af38b 100644 --- a/Gems/EMotionFX/Code/MCore/Source/Random.h +++ b/Gems/EMotionFX/Code/MCore/Source/Random.h @@ -64,22 +64,6 @@ namespace MCore */ static MCORE_INLINE float RandF(float minVal, float maxVal) { return minVal + (maxVal - minVal) * rand() / (float)RAND_MAX; } - /** - * Generate a uniform random float in a range of a given minimum and maximum. - * @param minVal The minimum value of the range. - * @param maxVal The maximum value of the range. - * @result A uniform random floating point number in range of [min..max]. - */ - static MCORE_INLINE float RandF(float minVal, float maxVal, unsigned int seed) { AZ_UNUSED(seed); return minVal + (maxVal - minVal) * rand() / (float)RAND_MAX; } - - /** - * Generate a uniform random float in a range of a given minimum and maximum. - * @param minVal The minimum value of the range. - * @param maxVal The maximum value of the range. - * @result A uniform random floating point number in range of [min..max]. - */ - static MCORE_INLINE float RandF(float minVal, float maxVal, LcgRandom& rand) { return minVal + (maxVal - minVal) * rand.GetRandomFloat(); } - /** * Generates a uniform random normalized direction vector, using floats. * @result A uniform random direction vector with a length of 1. From f91c605144411bff343012c58ffacd208dfb07bc Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Tue, 25 Jan 2022 14:57:16 -0800 Subject: [PATCH 35/36] Fix prefab/instance name inconsistency issue in automated testing's prefab utils (#7122) * Ensure to fire OnEditorEntityCreated notification in SandboxIntegrationManager::CreateNewEntityAtPosition Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * Ensure to fire OnEditorEntityCreated notification in SandboxIntegrationManager::CreateNewEntityAtPosition Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * convert test AreaNodes_DependentComponentsAdded to use prefab system Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * Prevent SetupEditorEntity being called twice Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * Fix prefab utils prefab naming issue Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * revert test changes Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * fix a grammatical error Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> --- .../editor_python_test_tools/prefab_utils.py | 68 +++++++++---------- .../Gem/PythonTests/Prefab/TestSuite_Main.py | 4 ++ .../Prefab/TestSuite_Main_Optimized.py | 6 +- .../CreatePrefab_UnderAnEntity.py | 3 +- .../CreatePrefab_WithSingleEntity.py | 3 +- .../DeletePrefab_ContainingASingleEntity.py | 3 +- .../DetachPrefab_UnderAnotherPrefab.py | 5 +- ...DuplicatePrefab_ContainingASingleEntity.py | 3 +- ...refab_FromCreatedPrefabWithSingleEntity.py | 34 ++++++++++ .../ReparentPrefab_UnderAnotherPrefab.py | 5 +- 10 files changed, 91 insertions(+), 43 deletions(-) create mode 100644 AutomatedTesting/Gem/PythonTests/Prefab/tests/instantiate_prefab/InstantiatePrefab_FromCreatedPrefabWithSingleEntity.py diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py index 016e01bc95..d0e51c4413 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/prefab_utils.py @@ -48,8 +48,8 @@ def wait_for_propagation(): # This is a helper class which contains some of the useful information about a prefab instance. class PrefabInstance: - def __init__(self, prefab_file_name: str = None, container_entity: EditorEntity = None): - self.prefab_file_name: str = prefab_file_name + def __init__(self, prefab_file_path: str = None, container_entity: EditorEntity = None): + self.prefab_file_path: str = prefab_file_path self.container_entity: EditorEntity = container_entity def __eq__(self, other): @@ -66,7 +66,7 @@ class PrefabInstance: See if this instance is valid to be used with other prefab operations. :return: Whether the target instance is valid or not. """ - return self.container_entity.id.IsValid() and self.prefab_file_name in Prefab.existing_prefabs + return self.container_entity.id.IsValid() and self.prefab_file_path in Prefab.existing_prefabs def has_editor_prefab_component(self) -> bool: """ @@ -131,7 +131,7 @@ class PrefabInstance: has_correct_parent = reparented_container_entity_parent_id.ToString() == parent_entity_id.ToString() assert has_correct_parent, "Prefab Instance reparented is *not* under the expected parent entity" - current_instance_prefab = Prefab.get_prefab(self.prefab_file_name) + current_instance_prefab = Prefab.get_prefab(self.prefab_file_path) current_instance_prefab.instances.remove(self) self.container_entity = reparented_container_entity @@ -161,46 +161,48 @@ class Prefab: :param file_path: A unique file path of the target prefab. :return: Whether the target prefab is loaded or not. """ - return file_path in Prefab.existing_prefabs - + for entry in Prefab.existing_prefabs: + Report.info(f"PrefabPath: '{entry}'") + + return get_prefab_file_path(file_path) in Prefab.existing_prefabs @classmethod def prefab_exists(cls, file_path: str) -> bool: """ Check if a prefab exists in the directory for files of prefab tests. - :param file_name: A unique file name of the target prefab. + :param file_path: A unique file path of the target prefab. :return: Whether the target prefab exists or not. """ return path.exists(get_prefab_file_path(file_path)) @classmethod - def get_prefab(cls, file_name: str) -> Prefab: + def get_prefab(cls, file_path: str) -> Prefab: """ Return a prefab which can be used immediately. - :param file_name: A unique file name of the target prefab. + :param file_path: A unique file path of the target prefab. :return: The prefab with given file name. """ - assert file_name, "Received an empty file_name" - if Prefab.is_prefab_loaded(file_name): - return Prefab.existing_prefabs[file_name] + assert file_path, "Received an empty file_path" + if Prefab.is_prefab_loaded(file_path): + return Prefab.existing_prefabs[get_prefab_file_path(file_path)] else: - assert Prefab.prefab_exists(file_name), f"Attempted to get a prefab \"{file_name}\" that doesn't exist" - new_prefab = Prefab(file_name) - Prefab.existing_prefabs[file_name] = Prefab(file_name) + assert Prefab.prefab_exists(file_path), f"Attempted to get a prefab \"{file_path}\" that doesn't exist" + new_prefab = Prefab(file_path) + Prefab.existing_prefabs[new_prefab.file_path] = new_prefab return new_prefab @classmethod - def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> tuple(Prefab, PrefabInstance): + def create_prefab(cls, entities: list[EditorEntity], file_path: str, prefab_instance_name: str=None) -> tuple(Prefab, PrefabInstance): """ Create a prefab in memory and return it. The very first instance of this prefab will also be created. :param entities: The entities that should form the new prefab (along with their descendants). - :param file_name: A unique file name of new prefab. - :param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as file_name. + :param file_path: A unique file path for new prefab. + :param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as the file name in file_path. :return: Created Prefab object and the very first PrefabInstance object owned by the prefab. """ - assert not Prefab.is_prefab_loaded(file_name), f"Can't create Prefab '{file_name}' since the prefab already exists" + assert not Prefab.is_prefab_loaded(file_path), f"Can't create Prefab '{file_path}' since the prefab already exists" - new_prefab = Prefab(file_name) + new_prefab = Prefab(file_path) entity_ids = [entity.id for entity in entities] create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', entity_ids, new_prefab.file_path) assert create_prefab_result.IsSuccess(), f"Prefab operation 'CreatePrefab' failed. Error: {create_prefab_result.GetError()}" @@ -210,15 +212,14 @@ class Prefab: children_entity_ids = container_entity.get_children_ids() assert len(children_entity_ids) == len(entities), f"Entity count of created prefab instance does *not* match the count of given entities." - - if prefab_instance_name: - container_entity.set_name(prefab_instance_name) - + wait_for_propagation() - new_prefab_instance = PrefabInstance(file_name, EditorEntity(container_entity_id)) + new_prefab_instance = PrefabInstance(new_prefab.file_path, EditorEntity(container_entity_id)) + if prefab_instance_name: + new_prefab_instance.container_entity.set_name(prefab_instance_name) new_prefab.instances.add(new_prefab_instance) - Prefab.existing_prefabs[file_name] = new_prefab + Prefab.existing_prefabs[new_prefab.file_path] = new_prefab return new_prefab, new_prefab_instance @classmethod @@ -250,7 +251,7 @@ class Prefab: assert False, "Not all entities and descendants in target prefabs are deleted." for instance in prefab_instances: - instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_name) + instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_path) instance_deleted_prefab.instances.remove(instance) instance = PrefabInstance() @@ -290,8 +291,7 @@ class Prefab: prefab_file_path = prefab.PrefabPublicRequestBus(bus.Broadcast, 'GetOwningInstancePrefabPath', duplicate_container_entity_id) assert prefab_file_path, "Returned file path should *not* be empty." - prefab_file_name = Path(prefab_file_path).stem - duplicate_instance_prefab = Prefab.get_prefab(prefab_file_name) + duplicate_instance_prefab = Prefab.get_prefab(prefab_file_path) duplicate_instance = PrefabInstance(prefab_file_path, EditorEntity(duplicate_container_entity_id)) duplicate_instance_prefab.instances.add(duplicate_instance) duplicate_instances.append(duplicate_instance) @@ -324,7 +324,7 @@ class Prefab: wait_for_propagation() - instance_owner_prefab = Prefab.get_prefab(prefab_instance.prefab_file_name) + instance_owner_prefab = Prefab.get_prefab(prefab_instance.prefab_file_path) instance_owner_prefab.instances.remove(prefab_instance) prefab_instance = PrefabInstance() @@ -346,13 +346,13 @@ class Prefab: container_entity_id = instantiate_prefab_result.GetValue() container_entity = EditorEntity(container_entity_id) - if name: - container_entity.set_name(name) - wait_for_propagation() new_prefab_instance = PrefabInstance(self.file_path, EditorEntity(container_entity_id)) - assert not new_prefab_instance in self.instances, "This prefab instance is already existed before this instantiation." + assert not new_prefab_instance in self.instances, "This prefab instance already existed before this instantiation." + if name: + new_prefab_instance.container_entity.set_name(name) + self.instances.add(new_prefab_instance) assert new_prefab_instance.is_at_position(prefab_position), "This prefab instance is *not* at expected position." diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py index 6e1f94d358..1fd48ee3c9 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main.py @@ -38,6 +38,10 @@ class TestAutomation(TestAutomationBase): from Prefab.tests.instantiate_prefab import InstantiatePrefab_ContainingASingleEntity as test_module self._run_prefab_test(request, workspace, editor, test_module) + def test_InstantiatePrefab_FromCreatedPrefabWithSingleEntity(self, request, workspace, editor, launcher_platform): + from Prefab.tests.instantiate_prefab import InstantiatePrefab_FromCreatedPrefabWithSingleEntity as test_module + self._run_prefab_test(request, workspace, editor, test_module) + def test_DeletePrefab_ContainingASingleEntity(self, request, workspace, editor, launcher_platform): from Prefab.tests.delete_prefab import DeletePrefab_ContainingASingleEntity as test_module self._run_prefab_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py index bf67b2c661..816b3b8e75 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/TestSuite_Main_Optimized.py @@ -45,8 +45,12 @@ class TestAutomationNoAutoTestMode(EditorTestSuite): class test_InstantiatePrefab_ContainingASingleEntity(EditorSharedTest): from .tests.instantiate_prefab import InstantiatePrefab_ContainingASingleEntity as test_module + class test_InstantiatePrefab_FromCreatedPrefabWithSingleEntity(EditorSharedTest): + from .tests.instantiate_prefab import InstantiatePrefab_FromCreatedPrefabWithSingleEntity as test_module + class test_DeletePrefab_ContainingASingleEntity(EditorSharedTest): from .tests.delete_prefab import DeletePrefab_ContainingASingleEntity as test_module class test_DuplicatePrefab_ContainingASingleEntity(EditorSharedTest): - from .tests.duplicate_prefab import DuplicatePrefab_ContainingASingleEntity as test_module \ No newline at end of file + from .tests.duplicate_prefab import DuplicatePrefab_ContainingASingleEntity as test_module + \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_UnderAnEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_UnderAnEntity.py index 5033c1da9c..4fdd5e4c4d 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_UnderAnEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_UnderAnEntity.py @@ -13,7 +13,8 @@ def CreatePrefab_UnderAnEntity(): Test is successful if the new instanced prefab of the child has the parent entity id """ - CAR_PREFAB_FILE_NAME = 'car_prefab' + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.prefab_utils import Prefab diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py index eb8a262a69..cd6d87a630 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/create_prefab/CreatePrefab_WithSingleEntity.py @@ -7,7 +7,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT def CreatePrefab_WithSingleEntity(): - CAR_PREFAB_FILE_NAME = 'car_prefab' + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/delete_prefab/DeletePrefab_ContainingASingleEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/delete_prefab/DeletePrefab_ContainingASingleEntity.py index 919168019e..e2c4ead034 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/delete_prefab/DeletePrefab_ContainingASingleEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/delete_prefab/DeletePrefab_ContainingASingleEntity.py @@ -7,7 +7,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT def DeletePrefab_ContainingASingleEntity(): - CAR_PREFAB_FILE_NAME = 'car_prefab' + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.prefab_utils import Prefab diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py index 69dbcfc89c..326d58023f 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/detach_prefab/DetachPrefab_UnderAnotherPrefab.py @@ -7,8 +7,9 @@ SPDX-License-Identifier: Apache-2.0 OR MIT def DetachPrefab_UnderAnotherPrefab(): - CAR_PREFAB_FILE_NAME = 'car_prefab2' - WHEEL_PREFAB_FILE_NAME = 'wheel_prefab2' + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' + WHEEL_PREFAB_FILE_NAME = Path(__file__).stem + 'wheel_prefab' import editor_python_test_tools.pyside_utils as pyside_utils diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/duplicate_prefab/DuplicatePrefab_ContainingASingleEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/duplicate_prefab/DuplicatePrefab_ContainingASingleEntity.py index e611303fbb..6acd303e2b 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/duplicate_prefab/DuplicatePrefab_ContainingASingleEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/duplicate_prefab/DuplicatePrefab_ContainingASingleEntity.py @@ -7,7 +7,8 @@ SPDX-License-Identifier: Apache-2.0 OR MIT def DuplicatePrefab_ContainingASingleEntity(): - CAR_PREFAB_FILE_NAME = 'car_prefab' + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.prefab_utils import Prefab diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/instantiate_prefab/InstantiatePrefab_FromCreatedPrefabWithSingleEntity.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/instantiate_prefab/InstantiatePrefab_FromCreatedPrefabWithSingleEntity.py new file mode 100644 index 0000000000..ddd1528533 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/instantiate_prefab/InstantiatePrefab_FromCreatedPrefabWithSingleEntity.py @@ -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 +""" + +def InstantiatePrefab_FromCreatedPrefabWithSingleEntity(): + + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' + + from editor_python_test_tools.editor_entity_utils import EditorEntity + from editor_python_test_tools.utils import Report + from editor_python_test_tools.prefab_utils import Prefab + + import Prefab.tests.PrefabTestUtils as prefab_test_utils + + prefab_test_utils.open_base_tests_level() + + # Creates a new entity at the root level + car_entity = EditorEntity.create_editor_entity() + car_prefab_entities = [car_entity] + + # Creates a prefab from the new entity + car_prefab, car_prefab_instance = Prefab.create_prefab(car_prefab_entities, CAR_PREFAB_FILE_NAME) + + # Instantiate another instance and verify + car_prefab_instance_2 = car_prefab.instantiate() + assert car_prefab_instance_2.is_valid(), "Failed to instantiate prefab" + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(InstantiatePrefab_FromCreatedPrefabWithSingleEntity) diff --git a/AutomatedTesting/Gem/PythonTests/Prefab/tests/reparent_prefab/ReparentPrefab_UnderAnotherPrefab.py b/AutomatedTesting/Gem/PythonTests/Prefab/tests/reparent_prefab/ReparentPrefab_UnderAnotherPrefab.py index 2c460a3298..49aeb97f63 100644 --- a/AutomatedTesting/Gem/PythonTests/Prefab/tests/reparent_prefab/ReparentPrefab_UnderAnotherPrefab.py +++ b/AutomatedTesting/Gem/PythonTests/Prefab/tests/reparent_prefab/ReparentPrefab_UnderAnotherPrefab.py @@ -7,8 +7,9 @@ SPDX-License-Identifier: Apache-2.0 OR MIT def ReparentPrefab_UnderAnotherPrefab(): - CAR_PREFAB_FILE_NAME = 'car_prefab' - WHEEL_PREFAB_FILE_NAME = 'wheel_prefab' + from pathlib import Path + CAR_PREFAB_FILE_NAME = Path(__file__).stem + 'car_prefab' + WHEEL_PREFAB_FILE_NAME = Path(__file__).stem + 'wheel_prefab' import editor_python_test_tools.pyside_utils as pyside_utils From 56e7e7073518847665638777b735ca7a64cdf9cd Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Tue, 25 Jan 2022 14:57:51 -0800 Subject: [PATCH 36/36] [development] properly pal-ify Android utilities in AzCore (#7147) Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- .../AzCore/Android/APKFileHandler.cpp | 0 .../Android}/AzCore/Android/APKFileHandler.h | 0 .../Android}/AzCore/Android/AndroidEnv.cpp | 0 .../Android}/AzCore/Android/AndroidEnv.h | 0 .../Android}/AzCore/Android/ApiLevel.h | 0 .../AzCore/Android/JNI/Internal/ClassName.h | 0 .../Android/JNI/Internal/JStringUtils.h | 0 .../Android/JNI/Internal/JStringUtils_impl.h | 0 .../AzCore/Android/JNI/Internal/Object_impl.h | 0 .../Android/JNI/Internal/Signature_impl.h | 0 .../Android}/AzCore/Android/JNI/JNI.cpp | 0 .../Android}/AzCore/Android/JNI/JNI.h | 0 .../Android}/AzCore/Android/JNI/Object.h | 0 .../Android}/AzCore/Android/JNI/Object_fwd.h | 0 .../Android}/AzCore/Android/JNI/Signature.h | 0 .../Android}/AzCore/Android/JNI/scoped_ref.h | 0 .../Android}/AzCore/Android/JNI/shared_ref.h | 0 .../Android}/AzCore/Android/Utils.cpp | 0 .../Android}/AzCore/Android/Utils.h | 0 .../Android/platform_android_files.cmake | 38 +++++++++---------- .../Android/Tests/JNI/Signature_tests.cpp | 0 .../Android/Tests/JNI/shared_ref_tests.cpp | 0 22 files changed, 19 insertions(+), 19 deletions(-) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/APKFileHandler.cpp (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/APKFileHandler.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/AndroidEnv.cpp (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/AndroidEnv.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/ApiLevel.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Internal/ClassName.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Internal/JStringUtils.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Internal/JStringUtils_impl.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Internal/Object_impl.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Internal/Signature_impl.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/JNI.cpp (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/JNI.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Object.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Object_fwd.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/Signature.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/scoped_ref.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/JNI/shared_ref.h (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/Utils.cpp (100%) rename Code/Framework/AzCore/{ => Platform/Android}/AzCore/Android/Utils.h (100%) rename Code/Framework/AzCore/{AzCore => Tests/Platform}/Android/Tests/JNI/Signature_tests.cpp (100%) rename Code/Framework/AzCore/{AzCore => Tests/Platform}/Android/Tests/JNI/shared_ref_tests.cpp (100%) diff --git a/Code/Framework/AzCore/AzCore/Android/APKFileHandler.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Android/APKFileHandler.cpp similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/APKFileHandler.cpp rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/APKFileHandler.cpp diff --git a/Code/Framework/AzCore/AzCore/Android/APKFileHandler.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/APKFileHandler.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/APKFileHandler.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/APKFileHandler.h diff --git a/Code/Framework/AzCore/AzCore/Android/AndroidEnv.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Android/AndroidEnv.cpp similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/AndroidEnv.cpp rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/AndroidEnv.cpp diff --git a/Code/Framework/AzCore/AzCore/Android/AndroidEnv.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/AndroidEnv.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/AndroidEnv.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/AndroidEnv.h diff --git a/Code/Framework/AzCore/AzCore/Android/ApiLevel.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/ApiLevel.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/ApiLevel.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/ApiLevel.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Internal/ClassName.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/ClassName.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Internal/ClassName.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/ClassName.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Internal/JStringUtils.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/JStringUtils.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Internal/JStringUtils.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/JStringUtils.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Internal/JStringUtils_impl.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/JStringUtils_impl.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Internal/JStringUtils_impl.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/JStringUtils_impl.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Internal/Object_impl.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/Object_impl.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Internal/Object_impl.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/Object_impl.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Internal/Signature_impl.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/Signature_impl.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Internal/Signature_impl.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Internal/Signature_impl.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/JNI.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/JNI.cpp similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/JNI.cpp rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/JNI.cpp diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/JNI.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/JNI.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/JNI.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/JNI.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Object.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Object.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Object.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Object.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Object_fwd.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Object_fwd.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Object_fwd.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Object_fwd.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/Signature.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Signature.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/Signature.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/Signature.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/scoped_ref.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/scoped_ref.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/scoped_ref.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/scoped_ref.h diff --git a/Code/Framework/AzCore/AzCore/Android/JNI/shared_ref.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/shared_ref.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/JNI/shared_ref.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/JNI/shared_ref.h diff --git a/Code/Framework/AzCore/AzCore/Android/Utils.cpp b/Code/Framework/AzCore/Platform/Android/AzCore/Android/Utils.cpp similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/Utils.cpp rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/Utils.cpp diff --git a/Code/Framework/AzCore/AzCore/Android/Utils.h b/Code/Framework/AzCore/Platform/Android/AzCore/Android/Utils.h similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/Utils.h rename to Code/Framework/AzCore/Platform/Android/AzCore/Android/Utils.h diff --git a/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake b/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake index 2ac4967b04..e72ae2a363 100644 --- a/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake +++ b/Code/Framework/AzCore/Platform/Android/platform_android_files.cmake @@ -62,25 +62,25 @@ set(FILES ../Common/UnixLike/AzCore/std/time_UnixLike.cpp AzCore/Utils/Utils_Android.cpp ../Common/Unimplemented/AzCore/Utils/Utils_Unimplemented.cpp - ../../AzCore/Android/AndroidEnv.cpp - ../../AzCore/Android/AndroidEnv.h - ../../AzCore/Android/APKFileHandler.cpp - ../../AzCore/Android/APKFileHandler.h - ../../AzCore/Android/ApiLevel.h - ../../AzCore/Android/Utils.cpp - ../../AzCore/Android/Utils.h - ../../AzCore/Android/JNI/JNI.cpp - ../../AzCore/Android/JNI/JNI.h - ../../AzCore/Android/JNI/Object.h - ../../AzCore/Android/JNI/Object_fwd.h - ../../AzCore/Android/JNI/scoped_ref.h - ../../AzCore/Android/JNI/shared_ref.h - ../../AzCore/Android/JNI/Signature.h - ../../AzCore/Android/JNI/Internal/ClassName.h - ../../AzCore/Android/JNI/Internal/JStringUtils.h - ../../AzCore/Android/JNI/Internal/JStringUtils_impl.h - ../../AzCore/Android/JNI/Internal/Object_impl.h - ../../AzCore/Android/JNI/Internal/Signature_impl.h + AzCore/Android/AndroidEnv.cpp + AzCore/Android/AndroidEnv.h + AzCore/Android/APKFileHandler.cpp + AzCore/Android/APKFileHandler.h + AzCore/Android/ApiLevel.h + AzCore/Android/Utils.cpp + AzCore/Android/Utils.h + AzCore/Android/JNI/JNI.cpp + AzCore/Android/JNI/JNI.h + AzCore/Android/JNI/Object.h + AzCore/Android/JNI/Object_fwd.h + AzCore/Android/JNI/scoped_ref.h + AzCore/Android/JNI/shared_ref.h + AzCore/Android/JNI/Signature.h + AzCore/Android/JNI/Internal/ClassName.h + AzCore/Android/JNI/Internal/JStringUtils.h + AzCore/Android/JNI/Internal/JStringUtils_impl.h + AzCore/Android/JNI/Internal/Object_impl.h + AzCore/Android/JNI/Internal/Signature_impl.h AzCore/Debug/Profiler_Platform.inl AzCore/Debug/Profiler_Android.inl ) diff --git a/Code/Framework/AzCore/AzCore/Android/Tests/JNI/Signature_tests.cpp b/Code/Framework/AzCore/Tests/Platform/Android/Tests/JNI/Signature_tests.cpp similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/Tests/JNI/Signature_tests.cpp rename to Code/Framework/AzCore/Tests/Platform/Android/Tests/JNI/Signature_tests.cpp diff --git a/Code/Framework/AzCore/AzCore/Android/Tests/JNI/shared_ref_tests.cpp b/Code/Framework/AzCore/Tests/Platform/Android/Tests/JNI/shared_ref_tests.cpp similarity index 100% rename from Code/Framework/AzCore/AzCore/Android/Tests/JNI/shared_ref_tests.cpp rename to Code/Framework/AzCore/Tests/Platform/Android/Tests/JNI/shared_ref_tests.cpp